/* eslint-disable no-useless-escape */
import * as THREE from 'three'
import { stats } from '../stats'
import { OrbitControls } from 'three/examples/jsm/controls/OrbitControls'

function createCourse26 (dom: HTMLElement) {
  const vertexShader = `
        uniform float time;
        varying vec2 vUv;

        void main()
        {
            vec3 posChanged = position;
            posChanged.x = posChanged.x*(abs(sin(time*1.0)));
            posChanged.y = posChanged.y*(abs(cos(time*1.0)));
            posChanged.z = posChanged.z*(abs(sin(time*1.0)));
            //gl_Position = projectionMatrix * modelViewMatrix * vec4(position*(abs(sin(time)/2.0)+0.5),1.0);
            gl_Position = projectionMatrix * modelViewMatrix * vec4(posChanged,1.0);
        }
    `
  const fragmentShader1 = `
    /*
        * Original shader from: 
        */
       
       #ifdef GL_ES
       //precision mediump float;
       #endif
       
       // glslsandbox
       uniform float time;
       uniform vec2 resolution;
       
       // shadertoy emulation
       #define iTime time
       #define iResolution resolution
       
       // poop - NOT EXACT ;)
       
       #define PI 3.14159267
       #define TAU 6.283189
       
       float dot2( in vec2 v ) { return dot(v,v); }
       float sdCappedCone( vec3 p, float h, float r1, float r2 )
       {
         vec2 q = vec2( length(p.xz), p.y );
         vec2 k1 = vec2(r2,h);
         vec2 k2 = vec2(r2-r1,2.0*h);
         vec2 ca = vec2(q.x-min(q.x,(q.y<0.0)?r1:r2), abs(q.y)-h);
         vec2 cb = q - k1 + k2*clamp( dot(k1-q,k2)/dot2(k2), 0.0, 1.0 );
         float s = (cb.x<0.0 && ca.y<0.0) ? -1.0 : 1.0;
         return s*sqrt( min(dot2(ca),dot2(cb)) );
       }
       
       float smax(float a,float b,float k)
       {
           k = -k;
           float h = clamp(0.5 + 0.5 * (b - a) / k, 0.0, 1.0);
           return mix(b, a, h) - k * h * (1.0 - h);
       }
       
       mat2 rot(float a)
       {
           float s=sin(a),c=cos(a);
           return mat2(c,s,-s,c);
       }
       
       float sdBox2D( in vec2 p, in vec2 b )
       {
           vec2 d = abs(p)-b;
           return length(max(d,0.0)) + min(max(d.x,d.y),0.0);
       }
       
       float sdHelix(vec3 p, float radius,float height, float coils, float pd,float ph)
       {
           coils =  coils / (height/PI);
           vec3 pp = vec3(normalize(p.xy)*radius, clamp(p.z, -height*0.5, height*0.5));
           float d1 = distance(p, pp);
           float d2 = asin(sin(p.z*coils + 0.5*atan(p.x,p.y)))/coils;
           float d=sdBox2D(vec2(d1,d2), vec2(pd,ph));
           return d;
       }
       
       float sdTurd(vec3 pos)
       {
           float radius = 2.5;
           float height = 4.0;
           float pd = radius-0.35;
           float ph = 0.01;
           float coils = 4.0;    
           float d1 = sdHelix(pos.xzy, radius,height, coils, pd, ph)-0.02;
           float d2 = sdCappedCone(pos,(height)*0.5,radius,0.0)-0.03;
           float d = smax(d2,-d1,0.45);
           return d*0.95;
       }
       
       float map( in vec3 pos )
       {
           pos.xz*=rot(fract(iTime*0.24)*6.28);
           return sdTurd(pos);
       }
       
       // http://iquilezles.org/www/articles/normalsSDF/normalsSDF.htm
       vec3 calcNormal( in vec3 pos )
       {
           vec2 e = vec2(1.0,-1.0)*0.5773;
           const float eps = 0.001;
           return normalize( e.xyy*map( pos + e.xyy*eps ) + 
                             e.yyx*map( pos + e.yyx*eps ) + 
                             e.yxy*map( pos + e.yxy*eps ) + 
                             e.xxx*map( pos + e.xxx*eps ) );
       }
       
       
       mat3 lookAtMatrix(vec3 from, vec3 to) {
           vec3 forward = normalize(to - from);
           vec3 right = normalize(cross(forward, vec3(0.0, 1.0, 0.0)));
           vec3 up = cross(right, forward);
           return mat3(right, up, forward);
       }
       float raycast(vec3 rayOrigin, vec3 rayDirection) {
           float maximumDistance = 30.0;
           float t = 0.0;
           for (int i = 0; i < 150; i++) {
               if (t > maximumDistance) {
                   break;
               }
               vec3 currentPosition = rayOrigin + rayDirection * t;
               float d = map(currentPosition);
               if (d < 0.0001) {
                   return t;
               }
               t += d;
           }
           return 0.0;
       }
       
       
       void mainImage(out vec4 fragColor, in vec2 fragCoord) {
           float angle = PI*0.4;
           vec3 rayOrigin = vec3(6.0 * cos(angle), 3.0+(sin(iTime*0.1)*1.5), 6.0 * sin(angle));
           vec3 targetPosition = vec3(0.0);
           mat3 cameraTransform = lookAtMatrix(rayOrigin, targetPosition);
           ivec2 sampleCount = ivec2(1.0, 1.0);
       
           vec2 uv = fragCoord;
           uv = uv / iResolution.xy;
           uv = (uv * 2.0) - 1.0;
           uv.x *= iResolution.x / iResolution.y;
           vec3 rayDirection = normalize(vec3(uv, 1.5));
           rayDirection = cameraTransform * rayDirection;
           float t = raycast(rayOrigin, rayDirection);
           vec3 color = vec3((1.0-abs(uv.y))*0.1);
           
           if (t > 0.0)
           {
               vec3 position = rayOrigin + rayDirection * t;
               vec3 n = calcNormal(position);
               
                   vec3 mycol = vec3(0.48,0.21,0.04);
                   vec3 pos = rayOrigin + t*rayDirection;
                   vec3 nor = n;
                   
                   vec3 dir = normalize(vec3(1.0,0.7,0.0));
                   vec3 ref = reflect(rayDirection, nor);
                   float spe = max(dot(ref, dir), 0.0);
                   vec3 spec = vec3(1.0) * pow(spe, 64.);
                   float dif = clamp( dot(nor,dir), 0.05, 1.0 );
                   color =  mycol*dif;
                   color+=spec;
           }
           fragColor = vec4(sqrt(color), 1.0);
       }
       
       // --------[ Original ShaderToy ends here ]---------- //
       
       void main(void)
       {
           mainImage(gl_FragColor, gl_FragCoord.xy);
       }
    `

  const fragmentShader2 = `
    #ifdef GL_ES
        //  precision mediump float;
          #endif
          
          // ↙
          //  ↙
          //   ↙
          // https://youtu.be/dQw4w9WgXcQ
          
          // compare algorithm performance, comment out line below to see previous performance:
          #define ANOTHER_ALGORITHM      // runs slower on ARM, so comment this out if mobile phone performance is priority
          
          vec2 uv;
          
          uniform float time;
          uniform vec2 resolution;
          
          const vec2 ch_size  = vec2(1.0, 2.0) * 0.6;              // character size (X,Y)
          const vec2 ch_space = ch_size + vec2(1.0, 1.0);    // character distance Vector(X,Y)
          const vec2 ch_start = vec2 (ch_space.x * -5., 1.); // start position
                vec2 ch_pos   = vec2 (0.0, 0.0);             // character position(X,Y)
          //      vec3 ch_color = vec3 (1.5, 0.75, 0.5);        // character color (R,G,B)
          //const vec3 bg_color = vec3 (0.2, 0.2, 0.2);        // background color (R,G,B)
          
          #define REPEAT_SIGN false // True/False; True=Multiple, False=Single
          
          /* 16 segment display...Akin to LED Display.
          
          Segment bit positions:
            __2__ __1__
           |\    |    /|
           | \   |   / |
           3  11 10 9  0
           |   \ | /   |
           |    \|/    |
            _12__ __8__
           |           |
           |    /|\    |
           4   / | \   7
           | 13 14  15 |
           | /   |   \ |
            __5__|__6__
          
          15 12 11 8 7  4 3  0
           |  | |  | |  | |  |
           0000 0000 0000 0000
          
          example: letter A
          
             12    8 7  4 3210
              |    | |  | ||||
           0001 0001 1001 1111
          
           binary to hex -> 0x119F
          */
          
          // split 16 Bit int into two 8 Bit int for mobile phones with ridiculous 1-byte int
          #define n0 ddigit(0x22,0xFF);
          #define n1 ddigit(0x02,0x81);
          #define n2 ddigit(0x11,0x77);
          #define n3 ddigit(0x11,0xE7);
          #define n4 ddigit(0x55,0x08);
          #define n5 ddigit(0x11,0xEE);
          #define n6 ddigit(0x11,0xFE);
          #define n7 ddigit(0x22,0x06);
          #define n8 ddigit(0x11,0xFF);
          #define n9 ddigit(0x11,0xEF);
          
          #define A ddigit(0x11,0x9F);
          #define B ddigit(0x92,0x7E);
          #define C ddigit(0x00,0x7E);
          #define D ddigit(0x44,0xE7);
          #define E ddigit(0x10,0x7E);
          #define F ddigit(0x10,0x1E);
          #define G ddigit(0x80,0x7E);
          #define H ddigit(0x11,0x99);
          #define I ddigit(0x44,0x66);
          #define J ddigit(0x44,0x36);
          #define K ddigit(0x92,0x18);
          #define L ddigit(0x00,0x78);
          #define M ddigit(0x0A,0x99);
          #define N ddigit(0x88,0x99);
          #define O ddigit(0x00,0xFF);
          #define P ddigit(0x11,0x1F);
          #define Q ddigit(0x80,0xFF);
          #define R ddigit(0x91,0x1F);
          #define S ddigit(0x88,0x66);
          #define T ddigit(0x44,0x06);
          #define U ddigit(0x00,0xF9);
          #define u ddigit(0x00,0xF0);
          #define V ddigit(0x22,0x18);
          #define W ddigit(0xA0,0x99);
          #define w ddigit(0xA0,0x90);
          #define X ddigit(0xAA,0x00);
          #define Y ddigit(0x4A,0x00);
          #define Z ddigit(0x22,0x66);
          #define _ ch_pos.x += ch_space.x;
          #define s_dot     ddigit(0,0);
          #define s_minus   ddigit(0x11,0x00);
          #define s_plus    ddigit(0x55,0x00);
          #define s_greater ddigit(0x28,0x00);
          #define s_less    ddigit(0x82,0x00);
          #define s_sqrt    ddigit(0x0C,0x02);
          #define s_sw      ddigit(0x55,0xAA);
          #define s_pow     ddigit(0x02,0x01);
          #define upper_u   ddigit(0x11,0x09);
          #define s_bra    ddigit(0x00,0x3C);
          #define s_ket    ddigit(0x00,0xC3);
          #define s_quotl    ddigit(0x04,0x01);
          #define s_quotr    ddigit(0x04,0x08);
          #define s_degrees    ddigit(0x05,0x03);
          #define s_ast    ddigit(0xFF,0x00);
          #define s_question ch_pos-=vec2(-.45,.4); ddigit(0,0); ch_pos+=vec2(-ch_space.x-.45,.4); ddigit(0x41,0x07); 
          #define s_exclam   ch_pos-=vec2(-.45,.4); ddigit(0,0); ch_pos+=vec2(-ch_space.x-.45,.4); ddigit(0x44,0x00);
          #define s_comma   ch_pos-=vec2(.45); ddigit(0x20,0x00); ch_pos+=vec2(.45);
          #define nl1 ch_pos = ch_start;  ch_pos.y -= 3.0;
          #define nl2 ch_pos = ch_start;  ch_pos.y -= 6.0;
          #define nl3 ch_pos = ch_start;  ch_pos.y -= 9.0;
          
          #ifdef ANOTHER_ALGORITHM
          float dseg1(vec2 p0, vec2 p1)
          {
              vec2 cp = vec2(uv.x-(uv.y*.5-ch_pos.y*.5-p0.y), uv.y) - ch_pos - p0;
              return distance(cp, vec2(0., clamp(cp.y, 0., p1.y-p0.y)) );   
          }
          float dseg2(vec2 p0, vec2 p1)
          {
              vec2 cp = vec2(uv.x+(uv.y*.5-.9-ch_pos.y*.5-p0.y), uv.y) - ch_pos - p0;
              return distance(cp, vec2(0., clamp(cp.y, 0., p1.y-p0.y)) );   
          }
          #else
          float dseg(vec2 p0, vec2 p1)
          {
              vec2 dir = normalize(p1 - p0);
              vec2 cp = (uv - ch_pos - p0) * mat2(dir.x, dir.y,-dir.y, dir.x);
              return distance(cp, clamp(cp, vec2(0), vec2(distance(p0, p1), 0)));   
          }
          #endif
          float dsegH(vec2 p0, vec2 p1) // avoiding matric ops
          {
              vec2 cp = uv - ch_pos - p0;
              //return distance(cp, clamp(cp, vec2(0), vec2(distance(p0, p1), 0)));   
              return distance(cp, vec2(clamp(cp.x, 0., p1.x-p0.x), 0.) );   
          }
          float dsegV(vec2 p0, vec2 p1) // avoiding matrix ops
          {
              vec2 cp = uv - ch_pos - p0;
              //return distance(cp, clamp(cp, vec2(0), vec2(0, distance(p0, p1))));   
              return distance(cp, vec2(0., clamp(cp.y, 0., p1.y-p0.y)) );   
          }
          
          bool bit(int n)
          {
              return (n/2)*2 != n;  
          }
          
          float d = 1e6;
          
          #ifdef ANOTHER_ALGORITHM  // Intel skylake GPU seems to prefer this 
          void ddigit(int n, int nn)
          {
              float v = 1e6;
              vec2 cp = uv - ch_pos;
              // better performance in this order, on Intel Iris 550 skylake  (WHY does order matter??)
              if (n == 0 && nn==0)     v = min(v, dsegH(vec2(-0.405, -1.000), vec2(-0.500, -1.000)));
              if (bit(nn/4)) v = min(v, dsegH(vec2( -0.438,  1.000), vec2(-0.063, 1.000)));
              if (bit(nn/2)) v = min(v, dsegH(vec2(0.063,  1.000), vec2(0.438,  1.000)));
              if (bit(nn/32)) v = min(v, dsegH(vec2(-0.438, -1.000), vec2(-0.063, -1.000)));
              if (bit(nn/64)) v = min(v, dsegH(vec2( 0.063, -1.000), vec2( 0.438, -1.000)));
              if (bit(n/1)) v = min(v, dsegH(vec2( 0.063,  0.000), vec2( 0.438, -0.000)));
              if (bit(n/16)) v = min(v, dsegH(vec2(-0.438,  0.000), vec2(-0.063, -0.000)));
              if (bit(nn/1)) v = min(v, dsegV(vec2( 0.500,  0.063), vec2( 0.500,  0.937)));
              if (bit(nn/128)) v = min(v, dsegV(vec2( 0.500, -0.938), vec2( 0.500, -0.063)));
              if (bit(n/4)) v = min(v, dsegV(vec2( 0.000,  0.063), vec2( 0.000,  0.937)));
              if (bit(n/64)) v = min(v, dsegV(vec2( 0.000, -0.938), vec2( 0.000, -0.063)));
              if (bit(nn/8)) v = min(v, dsegV(vec2(-0.500,  0.063), vec2(-0.500,  0.937)));
              if (bit(nn/16)) v = min(v, dsegV(vec2(-0.500, -0.938), vec2(-0.500, -0.063)));
              // matrix ops last
              if (bit(n/2)) v = min(v, dseg1(vec2( 0.063,  0.063), vec2( 0.063,  0.938)));
              if (bit(n/8)) v = min(v, dseg2(vec2(-0.963,  0.063), vec2(-1.338,  0.938)));
              if (bit(n/32)) v = min(v, dseg1(vec2(-0.963, -0.938), vec2(-0.963, -0.063)));
              if (bit(n/128)) v = min(v, dseg2(vec2( 0.063, -0.938), vec2( 0.063, -0.063)));
              ch_pos.x += ch_space.x;
              d = min(d, v);
          }
          #else // some GPU's may run faster with this
          void ddigit(int n, int nn)
          {
              float v = 1e6;
              vec2 cp = uv - ch_pos;
              if (n == 0 && nn == 0)     v = min(v, dseg(vec2(-0.405, -1.000), vec2(-0.500, -1.000)));
              if (bit(nn/1)) v = min(v, dseg(vec2( 0.500,  0.063), vec2( 0.500,  0.937)));
              if (bit(nn/2)) v = min(v, dseg(vec2( 0.438,  1.000), vec2( 0.063,  1.000)));
              if (bit(nn/4)) v = min(v, dseg(vec2(-0.063,  1.000), vec2(-0.438,  1.000)));
              if (bit(nn/8)) v = min(v, dseg(vec2(-0.500,  0.937), vec2(-0.500,  0.062)));
              if (bit(nn/16)) v = min(v, dseg(vec2(-0.500, -0.063), vec2(-0.500, -0.938)));
              if (bit(nn/32)) v = min(v, dseg(vec2(-0.438, -1.000), vec2(-0.063, -1.000)));
              if (bit(nn/64)) v = min(v, dseg(vec2( 0.063, -1.000), vec2( 0.438, -1.000)));
              if (bit(nn/128)) v = min(v, dseg(vec2( 0.500, -0.938), vec2( 0.500, -0.063)));
              if (bit(n/1)) v = min(v, dseg(vec2( 0.063,  0.000), vec2( 0.438, -0.000)));
              if (bit(n/2)) v = min(v, dseg(vec2( 0.063,  0.063), vec2( 0.438,  0.938)));
              if (bit(n/4)) v = min(v, dseg(vec2( 0.000,  0.063), vec2( 0.000,  0.937)));
              if (bit(n/8)) v = min(v, dseg(vec2(-0.063,  0.063), vec2(-0.438,  0.938)));
              if (bit(n/16)) v = min(v, dseg(vec2(-0.438,  0.000), vec2(-0.063, -0.000)));
              if (bit(n/32)) v = min(v, dseg(vec2(-0.063, -0.063), vec2(-0.438, -0.938)));
              if (bit(n/64)) v = min(v, dseg(vec2( 0.000, -0.938), vec2( 0.000, -0.063)));
              if (bit(n/128)) v = min(v, dseg(vec2( 0.063, -0.063), vec2( 0.438, -0.938)));
              ch_pos.x += ch_space.x;
              d = min(d, v);
          }
          #endif
          
          mat2 rotate(float a)
          {
              float c = cos(a);
              float s = sin(a);
              return mat2(c, s, -s, c);
          }
          vec3 hsv2rgb_smooth( in vec3 c )
          {
              vec3 rgb = clamp( abs(mod(c.x*6.0+vec3(0.0,4.0,2.0),6.0)-3.0)-1.0, 0.0, 1.0 );
          
              rgb = rgb*rgb*(3.0-2.0*rgb); // cubic smoothing
          
              return c.z * mix( vec3(1.0), rgb, c.y);
          }
          void main( void ) 
          {
              
              vec2 aspect = resolution.xy / resolution.y;
              uv = ( gl_FragCoord.xy / resolution.y ) - aspect / 2.0;
              float _d =  1.0-length(uv);
              uv *= 24.0 ;
              uv -= vec2(-10., 4.);
              //uv *= rotate(time+uv.x*0.05);
          
              vec3 ch_color = hsv2rgb_smooth(vec3(time*0.4+uv.y*0.1,0.5,1.0));
          
              vec3 bg_color = vec3(_d*0.4, _d*0.2, _d*0.1);
              uv.x += 0.5+sin(time+uv.y*0.7)*0.5;
              uv.x+=3.;
              ch_pos = ch_start;
          
                      nl1
                         _ _ _ _ s_greater   T H E _ P O Y O S _ A R E _ O Y O S 
                      nl2
                      _ _ _ _ A N D _ O Y O S _ A R E _ M O Y O S
                      nl3 
                      _ _ _ _ A N D _ M O Y O S _ A R E _ F O Y O S
              
                  
              vec3 color = mix(ch_color, bg_color, 1.0- (0.08 / d*2.0));  // shading
              gl_FragColor = vec4(color, 1.0);
          }
    `
  const fragmentShader3 = `
    // glslsandbox uniforms
        uniform float time;
        uniform vec2 resolution;
        
        // shadertoy emulation
        #define iTime time
        #define iResolution resolution
        #define HW_PERFORMANCE 0
        
        // Emulate a black texture
        #define texture(s, uv) vec4(0.0)
        #define textureLod(s, uv, lod) vec4(0.0)
        
        // --------[ Original ShaderToy begins here ]---------- //
        // Created by inigo quilez - iq/2015
        // License Creative Commons Attribution-NonCommercial-ShareAlike 3.0
        
        // Unfortunatelly, too similar to Dave Hoskins' shader. 
        // But it's one of my fav scenes from Wall-E, https://www.youtube.com/watch?v=vkAjOPqTghg
        // (well, the shader is only vagely inspired in that sene really)
        
        
        // number of samples (for blurring)
        //#define HIGH_QUALITY 
        
        
        #ifdef HIGH_QUALITY
          #define NS 8
        #else
          #if HW_PERFORMANCE==0
            #define NS 1
          #else
            #define NS 2
          #endif
        #endif
        
        
        //------------ primitives ------------
        
        
        float sdCapsule( vec3 p, vec3 a, vec3 b, float r )
        {
            vec3 pa = p-a, ba = b-a;
            float h = clamp( dot(pa,ba)/dot(ba,ba), 0.0, 1.0 );
            return length( pa - ba*h ) - r;
        }
        
        float sdSphere( in vec3 p, in vec4 s )
        {
            return length(p-s.xyz) - s.w;
        }
        
        float sdEllipsoid( in vec3 p, in vec3 c, in vec3 r )
        {
            p = p-c;
            float k0 = length(p/r);
            float k1 = length(p/(r*r));
            return k0*(k0-1.0)/k1;
        }
        
        float udRoundBox( vec3 p, vec3 b, float r )
        {
          return length(max(abs(p)-b,0.0))-r;
        }
        
        //------------ operators ------------
        
        float smin( float a, float b, float k )
        {
            float h = clamp( 0.5 + 0.5*(b-a)/k, 0.0, 1.0 );
            return mix( b, a, h ) - k*h*(1.0-h);
        }
        
        float smax( float a, float b, float k )
        {
            float h = clamp( 0.5 + 0.5*(b-a)/k, 0.0, 1.0 );
            return mix( a, b, h ) + k*h*(1.0-h);
        }
        
        vec2 minx( in vec2 a, in vec2 b )
        {
            return (a.x<b.x)?a:b;
        }
        
        //------------ maths ------------
        
        mat4 matRotate( in vec3 xyz )
        {
            vec3 si = sin(xyz);
            vec3 co = cos(xyz);
        
            return mat4( co.y*co.z,                co.y*si.z,               -si.y,       0.0,
                         si.x*si.y*co.z-co.x*si.z, si.x*si.y*si.z+co.x*co.z, si.x*co.y,  0.0,
                         co.x*si.y*co.z+si.x*si.z, co.x*si.y*si.z-si.x*co.z, co.x*co.y,  0.0,
                         0.0,                      0.0,                      0.0,        1.0 );
        }
        
        mat4 matTranslate( float x, float y, float z )
        {
            return mat4( 1.0, 0.0, 0.0, 0.0,
                         0.0, 1.0, 0.0, 0.0,
                         0.0, 0.0, 1.0, 0.0,
                         x,   y,   z,   1.0 );
        }
        
        mat4 matInverse( in mat4 m )
        {
            return mat4(
                m[0][0], m[1][0], m[2][0], 0.0,
                m[0][1], m[1][1], m[2][1], 0.0,
                m[0][2], m[1][2], m[2][2], 0.0,
                -dot(m[0].xyz,m[3].xyz),
                -dot(m[1].xyz,m[3].xyz),
                -dot(m[2].xyz,m[3].xyz),
                1.0 );
        }
        
        //--------------------------------------------
        
        float hash( float n )
        {
            return fract(sin(n)*1751.5453);
        }
        
        //--------------------------------------------
        
        
        mat4 mtxHead;
        
        vec2 map( vec3 p )
        {
            vec3 q = p; q.x = abs(q.x);
            vec3 hp = (mtxHead*vec4(p,1.0)).xyz;
        
            // body
            p.yz = mat2(0.98,-0.2,0.2,0.98)*p.yz;
            
            float d1 = sdEllipsoid( p, vec3(0.0,0.15,0.0), vec3(0.41,0.83,0.41) );
            float d2 = sdSphere( p, vec4(0.0,1.4,0.0,1.2) );
            float d9 = sdCapsule( q, vec3(0.5,-0.6,0.02), vec3(0.45,0.07,-0.02), 0.15 );
            float body = smax( d1, -d2, 0.03 );
            body = smax( body, -d9, 0.01 );
            
            
            // head
            float d3 = sdSphere( hp, vec4(0.0,0.0,0.0,0.4) );
            float d4 = sdSphere( hp, vec4(0.0,0.45,0.008,0.65) );
            float head = smax( d3, d4, 0.05 );
            // head hole    
            float d5 = sdEllipsoid( hp, vec3(0.0,0.0,0.4), vec3(0.48,0.3,0.2) );
            //d5 = smax( d5, sdSphere( hp, vec4(0.0,0.34,0.2, 0.46 )), 0.07 );
            d5 = smax( d5, sdSphere( hp, vec4(0.0,0.49,0.2, 0.6 )), 0.07 );
            head = smax( head, -d5, 0.025 );
            
            // face
            float d6 = sdSphere( hp, vec4(0.0,0.04,-0.05,0.41) );
            float m2 = smax(d6,d5,0.01);
        
            
            // arm
            float d7 = sdEllipsoid( q, vec3(0.5,-0.15,0.0), vec3(0.1,0.35,0.1) );
            float d8 = sdEllipsoid( q, vec3(0.54,-0.15,0.0), vec3(0.1,0.35,0.1) );
        //    d8 = sdCapsule( q, vec3(0.6,-0.6,0.02), vec3(0.55,0.09,-0.02), 0.15 );
            d7 = max( d7, d8 );
            float arm = d7;
            
        
            float m1 = min( min( body, head ), arm );
                                
            return minx( vec2(m1,0.0),
                         vec2(m2,1.0) );
        }
        
        vec3 calcNormal( in vec3 pos, in float eps )
        {
            vec2 e = vec2(1.0,-1.0)*0.5773*eps;
            return normalize( e.xyy*map( pos + e.xyy ).x + 
                              e.yyx*map( pos + e.yyx ).x + 
                              e.yxy*map( pos + e.yxy ).x + 
                              e.xxx*map( pos + e.xxx ).x );
        }
        
        float calcAO( in vec3 pos, in vec3 nor )
        {
            float occ = 0.0;
            for( int i=0; i<8; i++ )
            {
                //float h = 0.01 + 0.22*float(i)/7.0;
                float h = 0.01 + 0.21*float(i)/7.0;
                occ += (h-map( pos + h*nor )).x;
            }
            return clamp( 1.0 - 5.8*occ/8.0, 0.0, 1.0 );    
        }
        
        float calcSoftshadow( in vec3 ro, in vec3 rd, float k )
        {
            float res = 1.0;
            float t = 0.01;
        #ifdef HIGH_QUALITY
            for( int i=0; i<64; i++ )
        #else
            for( int i=0; i<16; i++ )
        #endif    
            {
                float h = map(ro + rd*t ).x;
                res = min( res, smoothstep(0.0,1.0,k*h/t) );
        #ifdef HIGH_QUALITY
                t += clamp( h, 0.01, 0.025 );
        #else        
                t += clamp( h, 0.04, 0.1 );
        #endif        
                if( res<0.01 ) break;
            }
            
            return clamp(res,0.0,1.0);
        }
        
        
        vec3 sundir = normalize( vec3(1.0,0.3,-0.5) );
        
        vec3 shade( in vec3 ro, in vec3 rd, in float t, float m )
        {
            float eps = 0.001;
            vec3 pos = ro + t*rd;
            vec3 nor = calcNormal( pos, eps );
            vec3 ref = reflect( rd, nor );
            
            vec3 mate = vec3(1.0,1.0,1.0);
            
            if( m<0.5 )
            {
                mate = vec3(0.7);
            }
            else
            {
                mate = vec3(0.0,0.0,0.0);
                
                vec2 uv = (mtxHead * vec4(pos,1.0)).xy;
        
                uv.x = abs(uv.x);
                uv -= vec2(0.11,0.565-0.5);
                vec2 st  = uv;
                uv = mat2(0.9,-0.4,0.4,0.9)*uv;
                vec3 eye = vec3(0.02,0.2,0.9)*1.9;
                eye *= 0.9 + 0.1*sin(512.0*st.x + sin(512.0*st.y));
                
                float eyesN = 1.0-smoothstep( 0.03, 0.06, length(uv * vec2(0.7,1.0)) );
                float eyesB = 1.0-smoothstep( 0.00,0.008,abs(st.y));
                float bl = smoothstep( 0.9,0.91, sin(10.0*iTime)*sin(3.0*iTime) );
                float eyes = mix( eyesN, eyesB, bl );
                mate = mix( mate, eye, eyes );
                
                mate += (0.01+mate)*0.9*smoothstep(-0.1,0.1,sin(st.y*400.0));
            }
            
            vec3 hal = normalize( sundir - rd );
            
            float fre = clamp( 1.0 + dot(nor,rd), 0.0, 1.0 );
            float occ = calcAO( pos, nor );
        
            float bak = clamp( dot(nor,normalize(vec3(-sundir.x,0.0,-sundir.z))), 0.0, 1.0 );
            float dif = clamp( dot(nor,sundir), 0.0, 1.0 );
            float spe = clamp( dot(nor,hal), 0.0, 1.0 );
            float sha = calcSoftshadow( pos, sundir, 8.0 ); 
            dif *= sha;
        
            vec3 col = 1.4*vec3(1.0,0.9,0.8)*dif +  0.8*vec3(0.2,0.28,0.35)*occ;
            col += vec3(1.2,1.0,0.8)*fre*(0.3+0.7*dif)*occ*3.5;
            col += vec3(0.4,0.3,0.2)*bak*occ;
            
            col *= mate;
            
            col += 3.5*vec3(0.3,0.4,0.5) * smoothstep( -0.1, 0.1, ref.y ) * (0.04 + 0.96*pow( fre, 5.0 )) * occ;
            col += 2.0*vec3(1.0)*pow( spe, 64.0 ) * (0.2 + 0.8*pow( fre, 5.0 )) * (occ*dif);
            
            col = pow( col, vec3(0.8,1.0,0.9) );
        
            col *= mix( vec3(0.3,0.2,0.1), vec3(1.0), smoothstep(-1.0,0.4,pos.y) );
            return col;        
        }
        
        vec2 intersect( in vec3 ro, in vec3 rd, const float maxdist )
        {
            vec2 res = vec2(-1.0);
            vec3 resP = vec3(0.0);
            float t = 3.0;
            for( int i=0; i<100; i++ )
            {
                vec3 p = ro + t*rd;
                vec2 h = map( p );
                res = vec2( t, h.y );
        
                if( h.x<(0.001*t) || t>maxdist ) break;
                
                t += h.x;//*0.5;
            }
            return res;
        }
        
        //----------------------------------------------------------------------------------
        vec2 mapTerrain( vec3 p )
        {
            float h = -2.5;
            h -= 1.5*sin( 5.0 + 0.2*p.z);
            h += 1.5*sin( 0.0 - 0.05*p.x - 0.05*p.z);
            float g = h;
            if( (p.y-h)<0.15 )
            h += 0.1*(textureLod( iChannel0, 0.1*p.xz, 0.0 ).x);
        
            float d1 = 0.2*(p.y-h);
                
            vec2 res = vec2( d1, 1.0 );
            
        #if 1
            if( -p.z>11.0 )
            {
            float ss = 4.0;
            vec3 q = p;
            vec2 id = floor( (q.xz+0.5*ss)/ss );
            q.xz = mod( q.xz+0.5*ss, ss ) - 0.5*ss;
            
        
            float r1 = hash(121.11*id.x+id.y*117.4);
            float r2 = hash( 71.72*id.x+id.y* 61.9);
            float r3 = hash( 31.74*id.x+id.y*317.1);
            mat4 rm = matRotate( vec3(1.0*r1,313.13*r2,0.2) );
            
            vec3 r = (rm*vec4(q,0.0)).xyz;
            r.y -= g + 0.25;
            
            float d2 = 0.8*udRoundBox( r, vec3(2.,0.01+0.2*r3,0.1+0.5*r3), 0.002 );
            res.x = min( d1, d2 );
            }
        #endif
                
            return res;
        }
        
        vec2 mapTerrainH( vec3 p )
        {
            float h = -2.5;
            h -= 1.5*sin( 5.0 + 0.2*p.z);
            h += 1.5*sin( 0.0 - 0.05*p.x - 0.05*p.z);
            float g = h;
            h += 0.1*(textureLod( iChannel0, 0.1*p.xz, 0.0 ).x);
        
            float d1 = 0.2*(p.y-h);
                
            vec2 res = vec2( d1, 1.0 );
            
        #if 1   
            if( -p.z>11.0 )
            {
            float ss = 4.0;
            vec3 q = p;
            vec2 id = floor( (q.xz+0.5*ss)/ss );
            q.xz = mod( q.xz+0.5*ss, ss ) - 0.5*ss;
            
        
            float r1 = hash(121.11*id.x+id.y*117.4);
            float r2 = hash( 71.72*id.x+id.y* 61.9);
            float r3 = hash( 31.74*id.x+id.y*317.1);
            mat4 rm = matRotate( vec3(1.0*r1,313.13*r2,0.2) );
            
            vec3 r = (rm*vec4(q,0.0)).xyz;
            r.y -= g + 0.25;
            
            float d2 = 0.8*udRoundBox( r, vec3(2.,0.01+0.2*r3,0.1+0.5*r3), 0.002 );
            res.x = min( d1, d2 );
            }
        #endif
                
            return res;
        }
        
        
        vec3 calcNormalTerrain( in vec3 pos, in float eps )
        {
            vec2 e = vec2(1.0,-1.0)*0.5773*eps;
            return normalize( e.xyy*mapTerrainH( pos + e.xyy ).x + 
                              e.yyx*mapTerrainH( pos + e.yyx ).x + 
                              e.yxy*mapTerrainH( pos + e.yxy ).x + 
                              e.xxx*mapTerrainH( pos + e.xxx ).x );
        }
        
        float calcSoftshadowTerrain( in vec3 ro, in vec3 rd, float k )
        {
            float res = 1.0;
            float t = 0.01;
            for( int i=0; i<16; i++ )
            {
                float h = mapTerrain(ro + rd*t ).x;
                res = min( res, smoothstep(0.0,1.0,k*h/t) );
                t += clamp( h, 0.04, 0.1 );
                if( res<0.01 ) break;
            }
            return clamp(res,0.0,1.0);
        }
        
        vec3 shadeTerrain( in vec3 ro, in vec3 rd, in float t, float m )
        {
            vec3 pos = ro + rd * t;
            vec3 nor = calcNormalTerrain( pos, 0.01 );
            vec3 hal = normalize( sundir - rd );
            
            vec3 col = texture( iChannel0, 0.01*pos.xz ).xyz*0.14 * vec3(1.1,1.0,0.9);
            
        
            float dif = clamp( dot(sundir,nor), 0.0, 1.0 );
            float spe = clamp( dot(nor,hal), 0.0, 1.0 );
            float amb = clamp( 0.3 + 0.7*nor.y, 0.0, 1.0 );
            //dif *= calcSoftshadowTerrain( pos+nor*0.1, sundir, 32.0 );
            vec3 lig = dif*vec3(3.0,2.0,1.5)*2.0 + pow(spe,8.0)*3.0*dif*4.0 + vec3(0.5,0.6,1.0)*amb;
                
            col *= lig;
        
            return col;
        }
            
        vec2 intersectTerrain( in vec3 ro, in vec3 rd, float maxdist )
        {
            vec2 res = vec2(-1.0);
            float t = 1.0;
            
            for( int i=0; i<256; i++ )
            {
                vec3 p = ro + t*rd;
                vec2 h = mapTerrain( p );
                res = vec2( t, h.y );
                if( h.x<(0.001*t) || t>maxdist ) break;
                t += h.x;
            }
            
            return res;
        }
        
        
        vec3 render( in vec3 ro, in vec3 rd )
        {
            vec3 col = mix( vec3(1.0,1.0,1.0),
                       vec3(0.8,0.6,0.4),
                       sqrt(max(rd.y,0.0)) );
        
            float sun = clamp( dot(rd,sundir), 0.0, 1.0 );
            col += 0.9*pow( sun, 64.0 );
            
            // terrain
            float maxdistTerrain = 200.0;
            float bp = (4.0-ro.y)/rd.y; if( bp>0.0 && bp<maxdistTerrain ) maxdistTerrain = bp;
            vec2 res = intersectTerrain( ro, rd, maxdistTerrain );
            float t = res.x;
            if( t < maxdistTerrain )
            {
                col = shadeTerrain( ro, rd, t, res.y );
            }
            
            // eve
            const float maxdist = 6.0;
            res = intersect( ro, rd, maxdist );
            if( res.x < maxdist )
            {
                t = res.x;
                col = shade( ro, rd, t, res.y );
            }
        
        
            // fog
            if( t<maxdistTerrain )
            {
                float f = exp(-0.03*t);
                col *= f;
                vec3 fcol = mix( vec3(1.0,0.9,0.9), vec3(1.1,0.8,0.4), exp(-0.01*t) );
                col += (1.0-f)*fcol*0.8;    
            }
        
            col += 0.4*pow( sun, 20.0 );
            
            return pow( col, vec3(0.45) );
        }
        
        mat3 setCamera( in vec3 ro, in vec3 rt, in float cr )
        {
            vec3 cw = normalize(rt-ro);
            vec3 cp = vec3(sin(cr), cos(cr),0.0);
            vec3 cu = normalize( cross(cw,cp) );
            vec3 cv = normalize( cross(cu,cw) );
            return mat3( cu, cv, -cw );
        }
        
        
        vec3 title( in vec3 col, in vec2 p )
        {
            return col;
        }
        
        
        void mainImage( out vec4 fragColor, in vec2 fragCoord )
        {
            float time = iTime;
        
            float rt = mod( time, 15.0 );
            float zo = step( 11.0, rt );
            float zf = clamp( (rt-11.0)/(15.0-11.0), 0.0, 1.0 );
        
            float an1 = sin(0.5*time*1.0+0.4)*(1.0-zo);
            float an2 = sin(0.5*time*1.3+0.0)*(1.0-zo);
            float an3 = sin(2.0*time);
            an1 = an1*an1*an1;
            an2 = an2*an2*an2;
            
            mat4 hRot = matRotate( vec3(-0.2*an1*an1*an1 - 0.1*zo,-1.0*an2*an2*an2, 0.0) );
            mat4 hTra = matTranslate( 0.0,0.5+0.015*an3-0.02*zo,0.11 );
        
            mtxHead = matInverse( hTra * hRot );
        
            vec2 q = fragCoord.xy/iResolution.xy;
        
            float an4 = 0.3 + 0.2*sin(0.04*time);
            vec3 ro = vec3( -5.2*sin(an4), 0.0+0.05*zo, 5.2*cos(an4) );
            
            vec3 ta = vec3(0.0,0.2+0.3*zo,0.0);
            ta += 0.02*cos( 1.0*time + vec3(0.0,2.0,3.0) )*(1.0-0.25*zo);
            ro += 0.02*cos( 1.0*time + vec3(1.0,3.5,5.0) )*(1.0-0.25*zo);
            mat3 ca = setCamera( ro, ta, 0.0 );
            float fl = 1.5 * (2.2 + 2.5*zo*(1.0+0.25*zf));
            
        
            vec3 col = vec3(0.0);
            for( int j=0; j<NS; j++ )
            for( int i=0; i<NS; i++ )
            {    
                vec2 o = (1.0+abs(q.x-0.5)*8.0*iResolution.x/850.0)*(vec2(float(i),float(j))/float(NS)-0.5);
                vec2 p = (-iResolution.xy+2.0*(fragCoord.xy+o))/iResolution.y;
        
                vec3 rd = normalize( ca * vec3(p,-fl) );
        
                col += render( ro, rd );
            }
            col /= float(NS*NS);
            
            // saturate
            col = mix( col, vec3(dot(col,vec3(0.333))), -0.1 );
        
            // vignette
            col *= 0.2 + 0.8*pow(16.0*q.x*q.y*(1.0-q.x)*(1.0-q.y), 0.1 );
        
            // letterbox
            col *= 1.0 - smoothstep( 0.4, 0.41, abs(q.y-0.5) );
        
            // flicker
            col *= 1.0 + 0.015*fract( 17.1*sin( 13.1*floor(12.0*iTime) ));
            
        
            col = title( col, q );
            
            fragColor = vec4( col, 1.0 );
        }
        
        // --------[ Original ShaderToy ends here ]---------- //
        
        void main(void)
        {
            mainImage(gl_FragColor, gl_FragCoord.xy);
        }`
  const fragmentShader4 = `
        uniform float time; // time
        uniform vec2  resolution; // resolution
        
        void main(void){
            vec3 destColor = vec3(0.51, 0.2, 0.1);
            vec2 p = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y);
            float a = atan(p.y / p.x) * 2.0; // Instead of * 2.0, try * 26 or * 128 and higher
            float l = 0.05 / abs(length(p) - 0.8 + sin(a + time * 4.5) * 0.1);
            destColor *= 1.9+ sin(a + time * 00.13) * 0.03;
            
            vec3 destColor2 = vec3(0.0, 0.2, 0.9);
            vec2 p2 = (gl_FragCoord.xy * 3.0 - resolution) / min(resolution.x, resolution.y); 
            float a2 = atan(p.y / p.x) * 3.0;
            float l2 = 0.05 / abs(length(p) + 0.1 - (tan(time/2.)+0.5) + sin(a + time * 13.5) * (0.1 * l));
            destColor2 *= ( 0.5 + sin(a + time * 00.03) * 0.03 ) * 4.0;
            
            vec3 destColor3 = vec3(0.2, 0.9, 0.35);
            vec2 p3 = (gl_FragCoord.xy * 2.0 - resolution) / min(resolution.x, resolution.y); 
            float a3 = atan(p.y / p.x) * 10.0;
            float l3 = 0.05 / abs(length(p) - 0.4 + sin(a + time * 23.5) * (0.1 * l2));
            destColor3 *= 0.5 + sin(a + time * 10.23) * 0.03;
            
            gl_FragColor = vec4(l*destColor + l2*destColor2 + l3*destColor3, 1.0);
        }
        `

  const fragmentShader5 = `
        /*
        * Original shader from: https://www.shadertoy.com/view/4tGfz3
        */
       
       #ifdef GL_ES
       precision highp float;
       #endif
       
       // glslsandbox uniforms
       uniform float time;
       uniform vec2 resolution;
       
       // shadertoy globals
       float iTime = 0.0;
       vec3  iResolution = vec3(0.0);
       const vec4 iMouse = vec4(0.0);
       
       // Emulate a black texture
       #define texture(s, uv) vec4(0.0)
       
       // --------[ Original ShaderToy begins here ]---------- //
       mat3 rotx(float a) { mat3 rot; rot[0] = vec3(1.0, 0.0, 0.0); rot[1] = vec3(0.0, cos(a), -sin(a)); rot[2] = vec3(0.0, sin(a), cos(a)); return rot; }
       mat3 roty(float a) { mat3 rot; rot[0] = vec3(cos(a), 0.0, sin(a)); rot[1] = vec3(0.0, 1.0, 0.0); rot[2] = vec3(-sin(a), 0.0, cos(a)); return rot; }
       mat3 rotz(float a) { mat3 rot; rot[0] = vec3(cos(a), -sin(a), 0.0); rot[1] = vec3(sin(a), cos(a), 0.0); rot[2] = vec3(0.0, 0.0, 1.0); return rot; }
       
       vec3 lightDir = normalize(vec3(1.5, 1.2, -1.0));
       const float groundH = .05;
       
       //https://www.shadertoy.com/view/4djSRW
       float hash(vec2 p)
       {
           #define HASHSCALE1 .1031
           vec3 p3  = fract(vec3(p.xyx) * HASHSCALE1);
           p3 += dot(p3, p3.yzx + 19.19);
           return fract((p3.x + p3.y) * p3.z);
       }
       
       
       // https://www.shadertoy.com/view/lsf3WH
       float noise( in vec2 p )
       {
           vec2 i = floor( p );
           vec2 f = fract( p );
           
           vec2 u = f*f*(3.0-2.0*f);
       
           return mix( mix( hash( i + vec2(0.0,0.0) ), 
                            hash( i + vec2(1.0,0.0) ), u.x),
                       mix( hash( i + vec2(0.0,1.0) ), 
                            hash( i + vec2(1.0,1.0) ), u.x), u.y);
       }
       
       
       // https://www.shadertoy.com/view/Ml2XDw
       float smax(float a, float b, float k)
       {
           return log(exp(k*a)+exp(k*b))/k;
       }
       
       // https://iquilezles.org/www/articles/distfunctions/distfunctions.htm
       float smin( float a, float b, float k )
       {
           float h = clamp( 0.5+0.5*(b-a)/k, 0.0, 1.0 );
           return mix( b, a, h ) - k*h*(1.0-h);
       }
       
       
       float sdBox( vec3 p, vec3 b )
       {
         vec3 d = abs(p) - b;
         return length(max(d,0.0))
                + min(max(d.x,max(d.y,d.z)),0.0); // remove this line for an only partially signed sdf 
       }
       
       
       float opBentBox(in vec3 p, in vec3 v , float bend)
       {
           float c = cos(bend*p.y);
           float s = sin(bend*p.y);
           mat2  m = mat2(c,-s,s,c);
           vec3  q = vec3(m*p.xy,p.z);
           return sdBox(q, v);
       }
       
       float sdRoundBox( vec3 p, vec3 b, float r )
       {
         vec3 d = abs(p) - b;
         return length(max(d,0.0)) - r
                + min(max(d.x,max(d.y,d.z)),0.0); // remove this line for an only partially signed sdf 
       }
       
       vec3 traceSphere(in vec3 ro, in vec3 rd, float r, out float t1, out float t2)
       {
           t1=t2=-1.0;
           vec3 X = ro + rd * (dot(normalize(-ro), rd)) * length(ro);
           float disc = r*r-pow(length(X), 2.0);
           if (disc < 0.0) return vec3(1000000.0);
           disc=sqrt(disc);
           vec3 p=X-disc*rd;
           t1=length(p-ro);t2=t1+disc*2.;
           return p;
       }
       
       const int NOTHING = 0;
       const int EYES = 1;
       
       struct HitInfo
       {
           int id;
           vec3 pos;
           float d;
       };
       
       
       
       HitInfo map(in vec3 rp)
       {
           HitInfo hi;
           rp.x = abs(rp.x);
           hi.id = NOTHING;
           
           // head
           float head = sdRoundBox(rp*1.7, vec3(.04, .05, .2)*1., 0.1);
           head += length(rp + vec3(0.0, 0.0, 0.1)) - 0.15;
           head = smin(head, length(rp * vec3(1.1, 1.3, 1.0)+ vec3(0.0, -0.1, -.07)) -0.08, 0.05);
           
           // nostrils
           float nostril = length(rp * vec3(6.0, 10.0, 1.0) + vec3(-0.27, -.5, 0.25)) - 0.1;
           head = max(head, -nostril );
           
           // ears
           float ear = length(rp * vec3(1.0, 1.0, 5.0) + vec3(-0.05, -.14, -0.5)) - 0.02;
           head = smin(head, ear, 0.02);
           // eyes
           vec3 eyePos = vec3(-0.02, -0.11, -0.02);
           float eye = length(rp + eyePos) - 0.03;
           
           if(eye < 0.0) 
           {
               hi.id = EYES;
               hi.pos = rp-eyePos;
               hi.d = eye;
               return hi;
           }
       
           head = min(head, eye);
           
           
           // mouth
           float mouth = sdBox(rotx(-0.2) * rp + vec3(0.0, 0.02, 0.215), vec3(0.15, 0.001 * max( -((rp.z))*25., 0.), 0.15));
           head = max(head, -mouth);
           
           // torso    
           float torso = length(rp * vec3(1.0, 1., 1.) + vec3(0.0, 0.12, -0.04)) - 0.13;
           torso = smin(torso, head, max(0.0, rp.z*1.));
           
           // legs
           float leg = sdRoundBox(rp + vec3(-.075, 0.2, -0.1), vec3(0.04, 0.3, 0.04)*.25, 0.04);
           float feet = sdBox(rp + vec3(-.075, 0.35, -0.07), vec3(0.07, 0.01, 0.06)*.25)-.025;
           leg = smin(leg, feet, 0.14);
           torso = smin(torso,leg, 0.04);
           
           // arms
              float arm = opBentBox(rotz(0.8)*(rp + vec3(-0.15, 0.09, -0.08)), vec3(0.01, 0.3, 0.07*max(1.0, -rp.y*0.))*.25, 5.) - .02;
           const float fingerWidth = .03;
           const float fingerBend = 40.;
           const float fingerX = -0.185;
           const float roundness = .004;
           const float spacing = 0.025;
           const float smoothen = .02;
           const float fingerY = .184;
           
           float finger1 = opBentBox(rp + vec3(fingerX, fingerY, -0.08-spacing), vec3(fingerWidth, .02, .01)*.2, fingerBend)-roundness;
           arm = smin(finger1, arm, smoothen);
       
           float finger2 = opBentBox(rp + vec3(fingerX, fingerY, -0.08), vec3(fingerWidth, .02, .01)*.2, fingerBend)-roundness;
           arm = smin(finger2, arm, smoothen);
       
           float finger3 = opBentBox(rp + vec3(fingerX, fingerY, -0.08+spacing), vec3(fingerWidth, .02, .01)*.2, fingerBend)-roundness;
           arm = smin(finger3, arm, smoothen);
           
           head = smin(arm, torso, 0.05);
           
           
           float body = min(head, torso);
           hi.d = body;
           return hi;
       }
       
       
       vec3 grad(in vec3 rp)
       {
           vec2 off = vec2(0.002, 0.0);
           vec3 g = vec3(map(rp + off.xyy).d - map(rp - off.xyy).d,
                         map(rp + off.yxy).d - map(rp - off.yxy).d,
                         map(rp + off.yyx).d - map(rp - off.yyx).d);
           return normalize(g);
       }
       
       
       float ao(in vec3 n, in vec3 rp)
       {
           float dist = 0.1;
           rp += n*dist;
           float occ = 0.;
           const int steps = 4;
           
           for (int i = 0; i < steps; ++i)
           {
               float d = map(rp).d;
               float o= clamp(d/(dist*float(i + 1)), 0.0, 1.0);
               
               occ += o;
               rp += n * dist;
           }
           
           occ /= float(steps);
           return occ;
                 
       }
       
       
       float fbm(in vec3 rp)
       {
           rp += vec3(5.0, 0.0, 0.0);
           vec2 p = rp.xz*.2;
           float f = noise(p) * 0.5;
           f += noise(p * 2.) * 0.5 * 0.5;
           f += noise(p * 4.) * 0.5 * 0.5 * 0.5;
           return f;
       }
       
       
       float sampleGround(in vec3 rp)
       {
           rp *= 3.;
           float texCol = 0.;
           float f = fbm(rp);
           texCol=1.-f;
           return texCol;
       }
       
       vec3 g_hitp = vec3(0.0);
       
       vec3 groundNormal(in vec3 rp)
       {
           float h0 = sampleGround(rp);
           vec2 off = vec2(0.1, 0.0);
           float h1 = h0 - sampleGround(rp + off.xyy);
           float h2 = h0 - sampleGround(rp + off.yyx);
           float h =.5;
           vec3 f=(vec3(off.x, h1*h, 0.0));
           vec3 u=(vec3(0.0, h2*h, off.x));
           vec3 n = normalize(cross(u, f));
           n += (1.0 - 2.0 * texture(iChannel3, rp.xz*2.).rgb)*.15;
           n = normalize(n);
           return n*vec3(-1.0, 1.0, -1.0);
       }
       
       
       bool trace(in vec3 rp, in vec3 rd, inout vec4 color)
       {
        
           bool hit = false;
           vec3 ro = rp;
           float dist = 0.0;
           HitInfo hi;
           
           // trace to character bounding sphere
           float t1, t2 = 0.0;
           traceSphere(ro, rd, .38, t1, t2);
           
           // character
           if(t1 > 0.0)
           {
               rp = ro + t1 * rd;
               for (int i = 0; i < 140; ++i)
               {
                   hi = map(rp);
                   dist = hi.d;
                   if(dist < 0.0)
                   {
                       hit = true;
                       break;
                   }
                   rp += rd * max(dist*.2, 0.001);
       
                   if(length(ro - rp) > t2) break;
       
               }
               rp += rd * dist*.5;
               hi = map(rp);
           }
           
           // character color
           vec3 albedo = vec3(180., 190., 200.)/255.;
           if(hi.id == EYES)
           {
               float off = .155;
               albedo = vec3(1.-smoothstep(off, off+.001, dot(hi.pos, normalize(vec3(0.0, 1., -1.0)))));
           }
                  
           
           if(hit)
           {
               
               color = vec4(.0);
               vec3 g = grad(rp);
               g_hitp = rp;
               
               //diff
               float d = dot(g, lightDir);
               float wrap = 0.8;
               d = d+wrap/(1.0+wrap);
               d = clamp(d, 0.1, 1.0);
               color.rgb += d*albedo*.5;
               
               //ao
               color.rgb += ao(g, rp)*vec3(239., 219., 159.)/255.*.15;
               
               // rim/fresn
               vec3 source = normalize(vec3(1.0, 2.0, 5.0));
               float rim = max(0.0, (dot(reflect(source, g), rd)));
               rim = pow(rim, 4.0)*.5;
               color.rgb += rim*vec3(.2, 0.2, 0.3);
               
               // some grounding for character + shadow
               color.rgb *= mix(vec3(1.0), vec3(0.2, 0.7, 0.9), 1.-smoothstep(-.7, 0.3, g.y));
               color.rgb *= 0.4 + 0.6 * smoothstep(-0.5, 0., rp.y);
           }
           
           float travel = length(ro - rp);
           vec3 hitp = ro;
           vec3 n = vec3(0.0, 1.0, 0.0);
           float t = (-dot(n, ro)+groundH)/dot(rd, n);
           
           // ground
           if(t > 0.)
           {
               hitp = ro + rd*t;
       
               float vdist = 0.0;
               
               // rougher tracing
               for (int i = 0; i < 40; ++i)
               {
                   float texCol = sampleGround(hitp);
                   vdist = hitp.y - (groundH - texCol);
                   if(vdist < 0.)
                   {
                       break;
                   }
       
                   hitp += rd*.05*log(2.+dot(ro-hitp, ro-hitp));
               }
               
               // hone into the surface
               for (int i = 0; i < 40; ++i)
               {
                   hitp += rd * vdist;
                   float texCol = sampleGround(hitp);
                   vdist = hitp.y - (groundH - texCol);
               }
               
               if(!hit || (travel > length(ro - hitp)))
               {
                   // dif
                   vec3 n = groundNormal(hitp);
                   float d = dot(n, normalize(vec3(0.0, 1., 0)));
                   d = clamp(d, 0.1, .99);
                   vec3 groundCol = vec3(0.7, 1., 1.) *pow(d, 4.)*.5;
                   
                   // rim            
                   float _rimd = 1.-(n.y * -rd.y);
                   float rimd = pow(_rimd, 8.0) * 4.;
                   rimd = clamp(rimd, 0.0, 1.0);
                   
                   groundCol += vec3(0.4, 0.6, 0.8) * rimd;
                   groundCol += texture(iChannel1, hitp.xz*.02).rrr * texture(iChannel3, hitp.xz).rrr;
                   
                   float specd = dot(reflect(normalize(vec3(0., -1., 0.)), n), -rd); 
                   specd = pow((clamp(specd, .0, 1.0)), 4.0) * .3;
                   groundCol += vec3(0.8, 0.9, 1.0)*specd;
                   
                   color.rgb = groundCol;
       
                   g_hitp = hitp;
                   
                   color.rgb *= 0.5 + 0.5 * smoothstep(0.0, .5, length(hitp.xz));
               }
           }
           
           return hit;
       }
       
           
       mat3 lookat(vec3 from, vec3 to)
       {
           vec3 f = normalize(to - from);
           vec3 _tmpr = normalize(cross(f, vec3(0.0, 1.0, 0.0)));
           vec3 u = normalize(cross(_tmpr, f));
           vec3 r = normalize(cross(u, f));
           return mat3(r, u, f);
       }
       
       
       void mainImage( out vec4 fragColor, in vec2 fragCoord )
       {
           vec2 uv = fragCoord.xy / iResolution.xy;
           uv -= vec2(0.5);
           uv.y /= iResolution.x / iResolution.y;
       
           vec2 im = 2.0 * ((iMouse.xy / iResolution.xy) - vec2(0.5));
           im.y *= .75;
           vec3 rd = normalize(vec3(uv, .4));
           vec3 rp = vec3(0.0, 1., -1.);
           vec3 _rp = rp;
           rp = roty(im.x) * rp;
           rp.y = (rotx(im.y) *_rp).y;
           
           if(iMouse.z <= 0.0)
           {
               float T = iTime * .2;
               rp.x = sin(T+.4);
               rp.y = sin(T) * 0.25 + .3;
               rp.z = -0.6;
           }
           
           rd = lookat(rp, vec3(0.0)) * rd;
           vec4 bgCol = vec4(.0, .1+rd.y*.2, 0.2, 0.15)*.15;
           bool hit = trace(rp, rd, fragColor);
           
           float light = smoothstep(5.0, 1.0, length(g_hitp));
           fragColor.rgb = mix(fragColor.rgb, vec3(0.0, 0.0, 0.02), .99-light);
           if(!hit)
           {
               fragColor.rgb = mix(fragColor.rgb, bgCol.rgb, smoothstep(-0.15, 0., rd.y));
               
               vec2 starCoord = vec2( atan(rd.x, rd.z), rd.y);
               vec3 stars = texture(iChannel0,starCoord).rrr*smoothstep(-1., .1, rd.y);
               stars = smoothstep(0.5, 1.0, stars-.3);
               stars *= texture(iChannel0, starCoord+vec2(iTime*.02)).rrr;
               fragColor.rgb += stars;
               
           }
           
           fragColor.rgb = pow(fragColor.rgb, vec3(1.0 / 2.2));
           
       }
       // --------[ Original ShaderToy ends here ]---------- //
       
       void main(void)
       {
           iTime = time;
           iResolution = vec3(resolution, 0.0);
       
           mainImage(gl_FragColor, gl_FragCoord.xy);
           gl_FragColor.a = 1.0;
       }
        `
  const fragmentShader6 = `
        #extension GL_OES_standard_derivatives : enable
  
        uniform float time;
        uniform vec2 resolution;
        
        // Planet Shadertoy. Created by Reinder Nijhoff 2015
        // @reindernijhoff
        //
        // https://www.shadertoy.com/view/4tjGRh
        // quick port by gigatron ..
        
        #define HIGH_QUALITY
        //#define MED_QUALITY
        //#define LOW_QUALITY
        //#define VERY_LOW_QUALITY
        
        const float PI = 3.14159265359;
        const float DEG_TO_RAD = (PI / 180.0);
        const float MAX = 10000.0;
        
        const float EARTH_RADIUS = 1000.;
        const float EARTH_ATMOSPHERE = 5.;
        const float EARTH_CLOUDS = 1.;
        
        const float RING_INNER_RADIUS = 1500.;
        const float RING_OUTER_RADIUS = 2300.;
        const float RING_HEIGHT = 2.;
        
        #ifdef HIGH_QUALITY
            const int   SEA_NUM_STEPS = 7;
            const int   TERRAIN_NUM_STEPS = 140;
            const int   ASTEROID_NUM_STEPS = 11;
            const int   ASTEROID_NUM_BOOL_SUB = 7;
            const int   RING_VOXEL_STEPS = 25;
            const float ASTEROID_MAX_DISTANCE = 1.1; 
            const int   FBM_STEPS = 4;
            const int   ATMOSPHERE_NUM_OUT_SCATTER = 5;
            const int   ATMOSPHERE_NUM_IN_SCATTER = 7;
        
            #define DISPLAY_LLAMEL
            #define DISPLAY_CLOUDS
            #define DISPLAY_CLOUDS_DETAIL
            #define DISPLAY_TERRAIN_DETAIL
        #endif
        
        #ifdef MED_QUALITY
            const int   SEA_NUM_STEPS = 6;
            const int   TERRAIN_NUM_STEPS = 100;
            const int   ASTEROID_NUM_STEPS = 10;
            const int   ASTEROID_NUM_BOOL_SUB = 6;
            const int   RING_VOXEL_STEPS = 24;
            const float ASTEROID_MAX_DISTANCE = 1.; 
            const int   FBM_STEPS = 4;
            const int   ATMOSPHERE_NUM_OUT_SCATTER = 4;
            const int   ATMOSPHERE_NUM_IN_SCATTER = 6;
            #define DISPLAY_CLOUDS
            #define DISPLAY_TERRAIN_DETAIL
            #define DISPLAY_CLOUDS_DETAIL
        #endif
        
        #ifdef LOW_QUALITY
            const int   SEA_NUM_STEPS = 5;
            const int   TERRAIN_NUM_STEPS = 75;
            const int   ASTEROID_NUM_STEPS = 9;
            const int   ASTEROID_NUM_BOOL_SUB = 5;
            const int   RING_VOXEL_STEPS = 20;
            const float ASTEROID_MAX_DISTANCE = .85; 
            const int   FBM_STEPS = 3;
            const int   ATMOSPHERE_NUM_OUT_SCATTER = 3;
            const int   ATMOSPHERE_NUM_IN_SCATTER = 5;
        #endif
        
        #ifdef VERY_LOW_QUALITY
            const int   SEA_NUM_STEPS = 4;
            const int   TERRAIN_NUM_STEPS = 60;
            const int   ASTEROID_NUM_STEPS = 7;
            const int   ASTEROID_NUM_BOOL_SUB = 4;
            const int   RING_VOXEL_STEPS = 16;
            const float ASTEROID_MAX_DISTANCE = .67; 
            const int   FBM_STEPS = 3;
            const int   ATMOSPHERE_NUM_OUT_SCATTER = 2;
            const int   ATMOSPHERE_NUM_IN_SCATTER = 4;
            #define HIDE_TERRAIN
        #endif
        
        const vec3  SUN_DIRECTION = vec3( .940721,  .28221626, .18814417 );
        const vec3  SUN_COLOR = vec3(.3, .21, .165);
        
         
        
        //-----------------------------------------------------
        // Noise functions
        //-----------------------------------------------------
        
        float hash( const in float n ) {
            return fract(sin(n)*43758.5453123);
        }
        float hash( const in vec2 p ) {
            float h = dot(p,vec2(127.1,311.7));
            return fract(sin(h)*43758.5453123);
        }
        float hash( const in vec3 p ) {
            float h = dot(p,vec3(127.1,311.7,758.5453123));
            return fract(sin(h)*43758.5453123);
        }
        vec3 hash31( const in float p) {
            vec3 h = vec3(1275.231,4461.7,7182.423) * p;
            return fract(sin(h)*43758.543123);
        }
        vec3 hash33( const in vec3 p) {
            return vec3( hash(p), hash(p.zyx), hash(p.yxz) );
        }
        
        float noise( const in  float p ) {    
            float i = floor( p );
            float f = fract( p );
            float u = f*f*(3.0-2.0*f);
            return -1.0+2.0* mix( hash( i + 0. ), hash( i + 1. ), u);
        }
        
        float noise( const in  vec2 p ) {    
            vec2 i = floor( p );
            vec2 f = fract( p );
            vec2 u = f*f*(3.0-2.0*f);
            return -1.0+2.0*mix( mix( hash( i + vec2(0.0,0.0) ), 
                             hash( i + vec2(1.0,0.0) ), u.x),
                        mix( hash( i + vec2(0.0,1.0) ), 
                             hash( i + vec2(1.0,1.0) ), u.x), u.y);
        }
        float noise( const in  vec3 x ) {
            vec3 p = floor(x);
            vec3 f = fract(x);
            f = f*f*(3.0-2.0*f);
            float n = p.x + p.y*157.0 + 113.0*p.z;
            return mix(mix(mix( hash(n+  0.0), hash(n+  1.0),f.x),
                           mix( hash(n+157.0), hash(n+158.0),f.x),f.y),
                       mix(mix( hash(n+113.0), hash(n+114.0),f.x),
                           mix( hash(n+270.0), hash(n+271.0),f.x),f.y),f.z);
        }
        
        float tri( const in vec2 p ) {
            return 0.5*(cos(6.2831*p.x) + cos(6.2831*p.y));
           
        }
        
        const mat2 m2 = mat2( 0.80, -0.60, 0.60, 0.80 );
        
        float fbm( in vec2 p ) {
            float f = 0.0;
            f += 0.5000*noise( p ); p = m2*p*2.02;
            f += 0.2500*noise( p ); p = m2*p*2.03;
            f += 0.1250*noise( p ); 
            
        #ifndef LOW_QUALITY
        #ifndef VERY_LOW_QUALITY
            p = m2*p*2.01;
            f += 0.0625*noise( p );
        #endif
        #endif
            return f/0.9375;
        }
        
        float fbm( const in vec3 p, const in float a, const in float f) {
            float ret = 0.0;    
            float amp = 1.0;
            float frq = 1.0;
            for(int i = 0; i < FBM_STEPS; i++) {
                float n = pow(noise(p * frq),2.0);
                ret += n * amp;
                frq *= f;
                amp *= a * (pow(n,0.2));
            }
            return ret;
        }
        
        //-----------------------------------------------------
        // Lightning functions
        //-----------------------------------------------------
        
        float diffuse( const in vec3 n, const in vec3 l) { 
            return clamp(dot(n,l),0.,1.);
        }
        
        float specular( const in vec3 n, const in vec3 l, const in vec3 e, const in float s) {    
            float nrm = (s + 8.0) / (3.1415 * 8.0);
            return pow(max(dot(reflect(e,n),l),0.0),s) * nrm;
        }
        
        float fresnel( const in vec3 n, const in vec3 e, float s ) {
            return pow(clamp(1.-dot(n,e), 0., 1.),s);
        }
        
        //-----------------------------------------------------
        // Math functions
        //-----------------------------------------------------
        
        vec2 rotate(float angle, vec2 v) {
            return vec2(cos(angle) * v.x + sin(angle) * v.y, cos(angle) * v.y - sin(angle) * v.x);
        }
        
        float boolSub(float a,float b) { 
            return max(a,-b); 
        }
        float sphere(vec3 p,float r) {
            return length(p)-r;
        }
        
        //-----------------------------------------------------
        // Intersection functions (by iq)
        //-----------------------------------------------------
        
        vec3 nSphere( in vec3 pos, in vec4 sph ) {
            return (pos-sph.xyz)/sph.w;
        }
        
        float iSphere( in vec3 ro, in vec3 rd, in vec4 sph ) {
            vec3 oc = ro - sph.xyz;
            float b = dot( oc, rd );
            float c = dot( oc, oc ) - sph.w*sph.w;
            float h = b*b - c;
            if( h<0.0 ) return -1.0;
            return -b - sqrt( h );
        }
        
        float iCSphereF( vec3 p, vec3 dir, float r ) {
            float b = dot( p, dir );
            float c = dot( p, p ) - r * r;
            float d = b * b - c;
            if ( d < 0.0 ) return -MAX;
            return -b + sqrt( d );
        }
        
        vec2 iCSphere2( vec3 p, vec3 dir, float r ) {
            float b = dot( p, dir );
            float c = dot( p, p ) - r * r;
            float d = b * b - c;
            if ( d < 0.0 ) return vec2( MAX, -MAX );
            d = sqrt( d );
            return vec2( -b - d, -b + d );
        }
        
        vec3 nPlane( in vec3 ro, in vec4 obj ) {
            return obj.xyz;
        }
        
        float iPlane( in vec3 ro, in vec3 rd, in vec4 pla ) {
            return (-pla.w - dot(pla.xyz,ro)) / dot( pla.xyz, rd );
        }
        
        //-----------------------------------------------------
        // Wet stone by TDM
        // 
        // https://www.shadertoy.com/view/ldSSzV
        //-----------------------------------------------------
        
        const float ASTEROID_TRESHOLD = 0.001;
        const float ASTEROID_EPSILON = 1e-6;
        const float ASTEROID_DISPLACEMENT = 0.1;
        const float ASTEROID_RADIUS = 0.13;
        
        const vec3  RING_COLOR_1 = vec3(0.42,0.3,0.2);
        const vec3  RING_COLOR_2 = vec3(0.51,0.41,0.32) * 0.2;
        
        float asteroidRock( const in vec3 p, const in vec3 id ) {  
            float d = sphere(p,ASTEROID_RADIUS);    
            for(int i = 0; i < ASTEROID_NUM_BOOL_SUB; i++) {
                float ii = float(i)+id.x;
                float r = (ASTEROID_RADIUS*2.5) + ASTEROID_RADIUS*hash(ii);
                vec3 v = normalize(hash31(ii) * 2.0 - 1.0);
                d = boolSub(d,sphere(p+v*r,r * 0.8));       
            }
            return d;
        }
        
        float asteroidMap( const in vec3 p, const in vec3 id) {
            float d = asteroidRock(p, id) + noise(p*4.0) * ASTEROID_DISPLACEMENT;
            return d;
        }
        
        float asteroidMapDetailed( const in vec3 p, const in vec3 id) {
            float d = asteroidRock(p, id) + fbm(p*4.0,0.4,2.96) * ASTEROID_DISPLACEMENT;
            return d;
        }
        
        void asteroidTransForm(inout vec3 ro, const in vec3 id ) {
            float xyangle = (id.x-.5)*time*2.;
            ro.xy = rotate( xyangle, ro.xy );
            
            float yzangle = (id.y-.5)*time*2.;
            ro.yz = rotate( yzangle, ro.yz );
        }
        
        void asteroidUnTransForm(inout vec3 ro, const in vec3 id ) {
            float yzangle = (id.y-.5)*time*2.;
            ro.yz = rotate( -yzangle, ro.yz );
        
            float xyangle = (id.x-.5)*time*2.;
            ro.xy = rotate( -xyangle, ro.xy );  
        }
        
        vec3 asteroidGetNormal(vec3 p, vec3 id) {
            asteroidTransForm( p, id );
            
            vec3 n;
            n.x = asteroidMapDetailed(vec3(p.x+ASTEROID_EPSILON,p.y,p.z), id);
            n.y = asteroidMapDetailed(vec3(p.x,p.y+ASTEROID_EPSILON,p.z), id);
            n.z = asteroidMapDetailed(vec3(p.x,p.y,p.z+ASTEROID_EPSILON), id);
            n = normalize(n-asteroidMapDetailed(p, id));
            
            asteroidUnTransForm( n, id );
            return n;
        }
        
        vec2 asteroidSpheretracing(vec3 ori, vec3 dir, vec3 id) {
            asteroidTransForm( ori, id );
            asteroidTransForm( dir, id );
            
            vec2 td = vec2(0.0);
            for(int i = 0; i < ASTEROID_NUM_STEPS; i++) {
                vec3 p = ori + dir * td.x;
                td.y = asteroidMap(p, id);
                if(td.y < ASTEROID_TRESHOLD) break;
                td.x += (td.y-ASTEROID_TRESHOLD) * 0.9;
            }
            return td;
        }
        
        vec3 asteroidGetStoneColor(vec3 p, float c, vec3 l, vec3 n, vec3 e) {
            return mix( diffuse(n,l)*RING_COLOR_1*SUN_COLOR, SUN_COLOR*specular(n,l,e,3.0), .5*fresnel(n,e,5.));    
        }
        
        //-----------------------------------------------------
        // Ring (by me ;))
        //-----------------------------------------------------
        
        const float RING_DETAIL_DISTANCE = 40.;
        const float RING_VOXEL_STEP_SIZE = .03;
        
        vec3 ringShadowColor( const in vec3 ro ) {
            if( iSphere( ro, SUN_DIRECTION, vec4( 0., 0., 0., EARTH_RADIUS ) ) > 0. ) {
                return vec3(0.);
            }
            return vec3(1.);
        }
        
        bool ringMap( const in vec3 ro ) {
            return ro.z < RING_HEIGHT/RING_VOXEL_STEP_SIZE && hash(ro)<.5;
        }
        
        vec4 renderRingNear( const in vec3 ro, const in vec3 rd ) { 
        // find startpoint 
            float d1 = iPlane( ro, rd, vec4( 0., 0., 1., RING_HEIGHT ) );
            float d2 = iPlane( ro, rd, vec4( 0., 0., 1., -RING_HEIGHT ) );
           
            if( d1 < 0. && d2 < 0. ) return vec4( 0. );
            
            float d = min( max(d1,0.), max(d2,0.) );
            
            if( d > ASTEROID_MAX_DISTANCE ) return vec4( 0. );
            
            vec3 ros = ro + rd*d;
            
            // avoid precision problems..
            vec2 mroxy = mod(ros.xy, vec2(10.));
            vec2 roxy = ros.xy - mroxy;
            ros.xy -= roxy;
            ros /= RING_VOXEL_STEP_SIZE;
            ros.xy -= vec2(.013,.112)*time*.5;
            
            vec3 pos = floor(ros);
            vec3 ri = 1.0/rd;
            vec3 rs = sign(rd);
            vec3 dis = (pos-ros + 0.5 + rs*0.5) * ri;
            
            float alpha = 0., dint;
            vec3 offset = vec3(0.), id, asteroidro;
            vec2 asteroid;
            
            for( int i=0; i<RING_VOXEL_STEPS; i++ ) {
                if( ringMap(pos) ) {
                    id = hash33(pos);
                    offset = id*(1.-2.*ASTEROID_RADIUS)+ASTEROID_RADIUS;
                    dint = iSphere( ros, rd, vec4(pos+offset, ASTEROID_RADIUS) );
                    
                    if( dint > 0. ) {
                        asteroidro = ros+rd*dint-(pos+offset);
                        asteroid = asteroidSpheretracing( asteroidro, rd, id );
                        
                        if( asteroid.y < .1 ) {
                            alpha = 1.;
                            break;    
                        }
                    }
        
                }
                vec3 mm = step(dis.xyz, dis.yxy) * step(dis.xyz, dis.zzx);
                dis += mm * rs * ri;
                pos += mm * rs;
            }
            
            if( alpha > 0. ) {       
                vec3 intersection = ros + rd*(asteroid.x+dint);
                vec3 n = asteroidGetNormal( asteroidro + rd*asteroid.x, id );
        
                vec3 col = asteroidGetStoneColor(intersection, .1, SUN_DIRECTION, n, rd);
        
                intersection *= RING_VOXEL_STEP_SIZE;
                intersection.xy += roxy;
                col *= ringShadowColor( intersection );
                 
                return vec4( col, 1.-smoothstep(0.4*ASTEROID_MAX_DISTANCE, 0.5* ASTEROID_MAX_DISTANCE, distance( intersection, ro ) ) );
            }
            
            return vec4(0.);
        }
        
        //-----------------------------------------------------
        // Ring (by me ;))
        //-----------------------------------------------------
        
        float renderRingFarShadow( const in vec3 ro, const in vec3 rd ) {
            // intersect plane
            float d = iPlane( ro, rd, vec4( 0., 0., 1., 0.) );
            
            if( d > 0. ) {
                vec3 intersection = ro + rd*d;
                float l = length(intersection.xy);
                
                if( l > RING_INNER_RADIUS && l < RING_OUTER_RADIUS ) {
                    return .5 + .5 * (.2+.8*noise( l*.07 )) * (.5+.5*noise(intersection.xy));
                }
            }
            return 0.;
        }
        
        vec4 renderRingFar( const in vec3 ro, const in vec3 rd, inout float maxd ) {
            // intersect plane
            float d = iPlane( ro, rd, vec4( 0., 0., 1., 0.) );
            
            if( d > 0. && d < maxd ) {
                maxd = d;
                vec3 intersection = ro + rd*d;
                float l = length(intersection.xy);
                
                if( l > RING_INNER_RADIUS && l < RING_OUTER_RADIUS ) {
                    float dens = .5 + .5 * (.2+.8*noise( l*.07 )) * (.5+.5*noise(intersection.xy));
                    vec3 col = mix( RING_COLOR_1, RING_COLOR_2, abs( noise(l*0.2) ) ) * abs(dens) * 1.5;
                    
                    col *= ringShadowColor( intersection );
                    col *= .8+.3*diffuse( vec3(0,0,1), SUN_DIRECTION );
                    col *= SUN_COLOR;
                    return vec4( col, dens );
                }
            }
            return vec4(0.);
        }
        
        vec4 renderRing( const in vec3 ro, const in vec3 rd, inout float maxd ) {
            vec4 far = renderRingFar( ro, rd, maxd );
            float l = length( ro.xy );
        
            if( abs(ro.z) < RING_HEIGHT+RING_DETAIL_DISTANCE 
                && l < RING_OUTER_RADIUS+RING_DETAIL_DISTANCE 
                && l > RING_INNER_RADIUS-RING_DETAIL_DISTANCE ) {
                 
                float d = iPlane( ro, rd, vec4( 0., 0., 1., 0.) );
                float detail = mix( .5 * noise( fract(ro.xy+rd.xy*d) * 92.1)+.25, 1., smoothstep( 0.,RING_DETAIL_DISTANCE, d) );
                far.xyz *= detail;    
            }
            
            // are asteroids neaded ?
            if( abs(ro.z) < RING_HEIGHT+ASTEROID_MAX_DISTANCE 
                && l < RING_OUTER_RADIUS+ASTEROID_MAX_DISTANCE 
                && l > RING_INNER_RADIUS-ASTEROID_MAX_DISTANCE ) {
                
                vec4 near = renderRingNear( ro, rd );
                far = mix( far, near, near.w );
                maxd=0.;
            }
                    
            return far;
        }
        
        //-----------------------------------------------------
        // Stars (by me ;))
        //-----------------------------------------------------
        
        vec4 renderStars( const in vec3 rd ) {
            vec3 rds = rd;
            vec3 col = vec3(0);
            float v = 1.0/( 2. * ( 1. + rds.z ) );
            
            vec2 xy = vec2(rds.y * v, rds.x * v);
            float s = noise(rds*134.);
            
            s += noise(rds*470.);
            s = pow(s,19.0) * 0.00001;
            if (s > 0.5) {
                vec3 backStars = vec3(s)*.5 * vec3(0.95,0.8,0.9); 
                col += backStars;
            }
            return   vec4( col, 1 ); 
        } 
        
        //-----------------------------------------------------
        // Atmospheric Scattering by GLtracy
        // 
        // https://www.shadertoy.com/view/lslXDr
        //-----------------------------------------------------
        
        const float ATMOSPHERE_K_R = 0.166;
        const float ATMOSPHERE_K_M = 0.0025;
        const float ATMOSPHERE_E = 12.3;
        const vec3  ATMOSPHERE_C_R = vec3( 0.3, 0.7, 1.0 );
        const float ATMOSPHERE_G_M = -0.85;
        
        const float ATMOSPHERE_SCALE_H = 4.0 / ( EARTH_ATMOSPHERE );
        const float ATMOSPHERE_SCALE_L = 1.0 / ( EARTH_ATMOSPHERE );
        
        const float ATMOSPHERE_FNUM_OUT_SCATTER = float(ATMOSPHERE_NUM_OUT_SCATTER);
        const float ATMOSPHERE_FNUM_IN_SCATTER = float(ATMOSPHERE_NUM_IN_SCATTER);
        
        const int   ATMOSPHERE_NUM_OUT_SCATTER_LOW = 2;
        const int   ATMOSPHERE_NUM_IN_SCATTER_LOW = 4;
        const float ATMOSPHERE_FNUM_OUT_SCATTER_LOW = float(ATMOSPHERE_NUM_OUT_SCATTER_LOW);
        const float ATMOSPHERE_FNUM_IN_SCATTER_LOW = float(ATMOSPHERE_NUM_IN_SCATTER_LOW);
        
        float atmosphericPhaseMie( float g, float c, float cc ) {
            float gg = g * g;
            float a = ( 1.0 - gg ) * ( 1.0 + cc );
            float b = 1.0 + gg - 2.0 * g * c;
            
            b *= sqrt( b );
            b *= 2.0 + gg;
            
            return 1.5 * a / b;
        }
        
        float atmosphericPhaseReyleigh( float cc ) {
            return 0.75 * ( 1.0 + cc );
        }
        
        float atmosphericDensity( vec3 p ){
            return exp( -( length( p ) - EARTH_RADIUS ) * ATMOSPHERE_SCALE_H );
        }
        
        float atmosphericOptic( vec3 p, vec3 q ) {
            vec3 step = ( q - p ) / ATMOSPHERE_FNUM_OUT_SCATTER;
            vec3 v = p + step * 0.5;
            
            float sum = 0.0;
            for ( int i = 0; i < ATMOSPHERE_NUM_OUT_SCATTER; i++ ) {
                sum += atmosphericDensity( v );
                v += step;
            }
            sum *= length( step ) * ATMOSPHERE_SCALE_L;
            
            return sum;
        }
        
        vec4 atmosphericInScatter( vec3 o, vec3 dir, vec2 e, vec3 l ) {
            float len = ( e.y - e.x ) / ATMOSPHERE_FNUM_IN_SCATTER;
            vec3 step = dir * len;
            vec3 p = o + dir * e.x;
            vec3 v = p + dir * ( len * 0.5 );
        
            float sumdensity = 0.;
            vec3 sum = vec3( 0.0 );
        
            for ( int i = 0; i < ATMOSPHERE_NUM_IN_SCATTER; i++ ) {
                vec3 u = v + l * iCSphereF( v, l, EARTH_RADIUS + EARTH_ATMOSPHERE );
                float n = ( atmosphericOptic( p, v ) + atmosphericOptic( v, u ) ) * ( PI * 4.0 );
                float dens = atmosphericDensity( v );
          
                float m = MAX;
                sum += dens * exp( -n * ( ATMOSPHERE_K_R * ATMOSPHERE_C_R + ATMOSPHERE_K_M ) ) 
                    * (1. - renderRingFarShadow( u, SUN_DIRECTION ) );
                 sumdensity += dens;
                
                v += step;
            }
            sum *= len * ATMOSPHERE_SCALE_L;
            
            float c  = dot( dir, -l );
            float cc = c * c;
            
            return vec4( sum * ( ATMOSPHERE_K_R * ATMOSPHERE_C_R * atmosphericPhaseReyleigh( cc ) + 
                                 ATMOSPHERE_K_M * atmosphericPhaseMie( ATMOSPHERE_G_M, c, cc ) ) * ATMOSPHERE_E, 
                                 clamp(sumdensity * len * ATMOSPHERE_SCALE_L,0.,1.));
        }
        
        float atmosphericOpticLow( vec3 p, vec3 q ) {
            vec3 step = ( q - p ) / ATMOSPHERE_FNUM_OUT_SCATTER_LOW;
            vec3 v = p + step * 0.5;
            
            float sum = 0.0;
            for ( int i = 0; i < ATMOSPHERE_NUM_OUT_SCATTER_LOW; i++ ) {
                sum += atmosphericDensity( v );
                v += step;
            }
            sum *= length( step ) * ATMOSPHERE_SCALE_L;
            
            return sum;
        }
        
        vec3 atmosphericInScatterLow( vec3 o, vec3 dir, vec2 e, vec3 l ) {
            float len = ( e.y - e.x ) / ATMOSPHERE_FNUM_IN_SCATTER_LOW;
            vec3 step = dir * len;
            vec3 p = o + dir * e.x;
            vec3 v = p + dir * ( len * 0.5 );
        
            vec3 sum = vec3( 0.0 );
        
            for ( int i = 0; i < ATMOSPHERE_NUM_IN_SCATTER_LOW; i++ ) {
                vec3 u = v + l * iCSphereF( v, l, EARTH_RADIUS + EARTH_ATMOSPHERE );
                float n = ( atmosphericOpticLow( p, v ) + atmosphericOpticLow( v, u ) ) * ( PI * 4.0 );
                float m = MAX;
                sum += atmosphericDensity( v ) * exp( -n * ( ATMOSPHERE_K_R * ATMOSPHERE_C_R + ATMOSPHERE_K_M ) );
                v += step;
            }
            sum *= len * ATMOSPHERE_SCALE_L;
            
            float c  = dot( dir, -l );
            float cc = c * c;
            
            return sum * ( ATMOSPHERE_K_R * ATMOSPHERE_C_R * atmosphericPhaseReyleigh( cc ) + 
                           ATMOSPHERE_K_M * atmosphericPhaseMie( ATMOSPHERE_G_M, c, cc ) ) * ATMOSPHERE_E;
        }
        
        vec4 renderAtmospheric( const in vec3 ro, const in vec3 rd, inout float d ) {    
            // inside or outside atmosphere?
            vec2 e = iCSphere2( ro, rd, EARTH_RADIUS + EARTH_ATMOSPHERE );
            vec2 f = iCSphere2( ro, rd, EARTH_RADIUS );
                
            if( length(ro) <= EARTH_RADIUS + EARTH_ATMOSPHERE ) {
                if( d < e.y ) {
                    e.y = d;
                }
                d = e.y;
                e.x = 0.;
                
                if ( iSphere( ro, rd, vec4(0,0,0,EARTH_RADIUS)) > 0. ) {
                    d = iSphere( ro, rd, vec4(0,0,0,EARTH_RADIUS));
                }
            } else {
                if(  iSphere( ro, rd, vec4(0,0,0,EARTH_RADIUS + EARTH_ATMOSPHERE )) < 0. ) return vec4(0.);
                
                if ( e.x > e.y ) {
                    d = MAX;
                    return vec4(0.);
                }
                d = e.y = min( e.y, f.x );
            }
            return atmosphericInScatter( ro, rd, e, SUN_DIRECTION );
        }
        
        vec3 renderAtmosphericLow( const in vec3 ro, const in vec3 rd ) {    
            vec2 e = iCSphere2( ro, rd, EARTH_RADIUS + EARTH_ATMOSPHERE );
            e.x = 0.;
            return atmosphericInScatterLow( ro, rd, e, SUN_DIRECTION );
        }
        
        //-----------------------------------------------------
        // Seascape by TDM
        // 
        // https://www.shadertoy.com/view/Ms2SD1
        //-----------------------------------------------------
        
        const int   SEA_ITER_GEOMETRY = 3;
        const int   SEA_ITER_FRAGMENT = 5;
        
        const float SEA_EPSILON = 1e-3;
        #define     SEA_EPSILON_NRM(0.1 / resolution.x)
        const float SEA_HEIGHT = 0.6;
        const float SEA_CHOPPY = 4.0;
        const float SEA_SPEED = 0.8;
        const float SEA_FREQ = 0.16;
        const vec3  SEA_BASE = vec3(0.1,0.19,0.22);
        const vec3  SEA_WATER_COLOR = vec3(0.8,0.9,0.6);
        float       SEA_TIME = 0.0;
        const mat2  sea_octave_m = mat2(1.6,1.2,-1.2,1.6);
        
        float seaOctave( in vec2 uv, const in float choppy) {
            uv += noise(uv);        
            vec2 wv = 1.0-abs(sin(uv));
            vec2 swv = abs(cos(uv));    
            wv = mix(wv,swv,wv);
            return pow(1.0-pow(wv.x * wv.y,0.65),choppy);
        }
        
        float seaMap(const in vec3 p) {
            float freq = SEA_FREQ;
            float amp = SEA_HEIGHT;
            float choppy = SEA_CHOPPY;
            vec2 uv = p.xz; uv.x *= 0.75;
            
            float d, h = 0.0;    
            for(int i = 0; i < SEA_ITER_GEOMETRY; i++) {        
                d = seaOctave((uv+SEA_TIME)*freq,choppy);
                d += seaOctave((uv-SEA_TIME)*freq,choppy);
                h += d * amp;        
                uv *= sea_octave_m; freq *= 1.9; amp *= 0.22;
                choppy = mix(choppy,1.0,0.2);
            }
            return p.y - h;
        }
        
        float seaMapHigh(const in vec3 p) {
            float freq = SEA_FREQ;
            float amp = SEA_HEIGHT;
            float choppy = SEA_CHOPPY;
            vec2 uv = p.xz; uv.x *= 0.75;
            
            float d, h = 0.0;    
            for(int i = 0; i < SEA_ITER_FRAGMENT; i++) {        
                d = seaOctave((uv+SEA_TIME)*freq,choppy);
                d += seaOctave((uv-SEA_TIME)*freq,choppy);
                h += d * amp;        
                uv *= sea_octave_m; freq *= 1.9; amp *= 0.22;
                choppy = mix(choppy,1.0,0.2);
            }
            return p.y - h;
        }
        
        vec3 seaGetColor( const in vec3 n, vec3 eye, const in vec3 l, const in float att, 
                          const in vec3 sunc, const in vec3 upc, const in vec3 reflected) {  
            vec3 refracted = SEA_BASE * upc + diffuse(n,l) * SEA_WATER_COLOR * 0.12 * sunc; 
            vec3 color = mix(refracted,reflected,fresnel(n, -eye, 3.)*.65 );
            
            color += upc*SEA_WATER_COLOR * (att * 0.18);
            color += sunc * vec3(specular(n,l,eye,60.0));
            
            return color;
        }
        
        vec3 seaGetNormal(const in vec3 p, const in float eps) {
            vec3 n;
            n.y = seaMapHigh(p);    
            n.x = seaMapHigh(vec3(p.x+eps,p.y,p.z)) - n.y;
            n.z = seaMapHigh(vec3(p.x,p.y,p.z+eps)) - n.y;
            n.y = eps;
            return normalize(n);
        }
        
        float seaHeightMapTracing(const in vec3 ori, const in vec3 dir, out vec3 p) {  
            float tm = 0.0;
            float tx = 1000.0;    
            float hx = seaMap(ori + dir * tx);
            if(hx > 0.0) return tx;   
            float hm = seaMap(ori + dir * tm);    
            float tmid = 0.0;
            for(int i = 0; i < SEA_NUM_STEPS; i++) {
                tmid = mix(tm,tx, hm/(hm-hx));                   
                p = ori + dir * tmid;                   
                float hmid = seaMap(p);
                if(hmid < 0.0) {
                    tx = tmid;
                    hx = hmid;
                } else {
                    tm = tmid;
                    hm = hmid;
                }
            }
            return tmid;
        }
        
        vec3 seaTransform( in vec3 x ) {
            x.yz = rotate( 0.8, x.yz );
            return x;
        }
        
        vec3 seaUntransform( in vec3 x ) {
            x.yz = rotate( -0.8, x.yz );
            return x;
        }
        
        void renderSea( const in vec3 ro, const in vec3 rd, inout vec3 n, inout float att ) {    
            vec3 p,
            rom = seaTransform(ro),
            rdm = seaTransform(rd);
            
            rom.y -= EARTH_RADIUS;
            rom *= 1000.;
            rom.xz += vec2(3.1,.2)*time;
        
            SEA_TIME = time * SEA_SPEED;
            
            seaHeightMapTracing(rom,rdm,p);
            float squareddist = dot(p - rom, p-rom );
            n = seaGetNormal(p, squareddist * SEA_EPSILON_NRM );
            
            n = seaUntransform(n);
            
            att = clamp(SEA_HEIGHT+p.y, 0.,1.);
        }
        
        //-----------------------------------------------------
        // Terrain based on Elevated and Terrain Tubes by IQ
        //
        // https://www.shadertoy.com/view/MdX3Rr
        // https://www.shadertoy.com/view/4sjXzG
        //-----------------------------------------------------
        
        #ifndef HIDE_TERRAIN
        
        const mat2 terrainM2 = mat2(1.6,-1.2,1.2,1.6);
        
        float terrainLow( vec2 p ) {
            p *= 0.0013;
        
            float s = 1.0;
            float t = 0.0;
            for( int i=0; i<2; i++ ) {
                t += s*tri( p );
                s *= 0.5 + 0.1*t;
                p = 0.97*terrainM2*p + (t-0.5)*0.12;
            }
            return t*33.0;
        }
        
        float terrainMed( vec2 p ) {
            p *= 0.0013;
        
            float s = 1.0;
            float t = 0.0;
            for( int i=0; i<6; i++ ) {
                t += s*tri( p );
                s *= 0.5 + 0.1*t;
                p = 0.97*terrainM2*p + (t-0.5)*0.12;
            }
                    
            return t*33.0;
        }
        
        float terrainHigh( vec2 p ) {
            vec2 q = p;
            p *= 0.0013;
        
            float s = 1.0;
            float t = 0.0;
            for( int i=0; i<7; i++ ) {
                t += s*tri( p );
                s *= 0.5 + 0.1*t;
                p = 0.97*terrainM2*p + (t-0.5)*0.12;
            }
            
            t += t*0.015*fbm( q );
            return t*33.0;
        }
        
        float terrainMap( const in vec3 pos ) {
            return pos.y - terrainMed(pos.xz);  
        }
        
        float terrainMapH( const in vec3 pos ) {
            float y = terrainHigh(pos.xz);
            float h = pos.y - y;
            return h;
        }
        
        float terrainIntersect( in vec3 ro, in vec3 rd, in float tmin, in float tmax ) {
            float t = tmin;
            for( int i=0; i<TERRAIN_NUM_STEPS; i++ ) {
                vec3 pos = ro + t*rd;
                float res = terrainMap( pos );
                if( res<(0.001*t) || t>tmax  ) break;
                t += res*.9;
            }
        
            return t;
        }
        
        float terrainCalcShadow(in vec3 ro, in vec3 rd ) {
            vec2  eps = vec2(150.0,0.0);
            float h1 = terrainMed( ro.xz );
            float h2 = terrainLow( ro.xz );
            
            float d1 = 10.0;
            float d2 = 80.0;
            float d3 = 200.0;
            float s1 = clamp( 1.0*(h1 + rd.y*d1 - terrainMed(ro.xz + d1*rd.xz)), 0.0, 1.0 );
            float s2 = clamp( 0.5*(h1 + rd.y*d2 - terrainMed(ro.xz + d2*rd.xz)), 0.0, 1.0 );
            float s3 = clamp( 0.2*(h2 + rd.y*d3 - terrainLow(ro.xz + d3*rd.xz)), 0.0, 1.0 );
        
            return min(min(s1,s2),s3);
        }
        vec3 terrainCalcNormalHigh( in vec3 pos, float t ) {
            vec2 e = vec2(1.0,-1.0)*0.001*t;
        
            return normalize( e.xyy*terrainMapH( pos + e.xyy ) + 
                              e.yyx*terrainMapH( pos + e.yyx ) + 
                              e.yxy*terrainMapH( pos + e.yxy ) + 
                              e.xxx*terrainMapH( pos + e.xxx ) );
        }
        
        vec3 terrainCalcNormalMed( in vec3 pos, float t ) {
            float e = 0.005*t;
            vec2  eps = vec2(e,0.0);
            float h = terrainMed( pos.xz );
            return normalize(vec3( terrainMed(pos.xz-eps.xy)-h, e, terrainMed(pos.xz-eps.yx)-h ));
        }
        
        vec3 terrainTransform( in vec3 x ) {
            x.zy = rotate( -.83, x.zy );
            return x;
        }
        
        vec3 terrainUntransform( in vec3 x ) {
            x.zy = rotate( .83, x.zy );
            return x;
        }
        
        
        float llamelTime;
        const float llamelScale = 5.;
        
        vec3 llamelPosition() {
            llamelTime = time*2.5;
            vec2 pos = vec2( -400., 135.-llamelTime*0.075* llamelScale);
            return vec3( pos.x, terrainMed( pos ), pos.y );
        }
        
        vec3 terrainShade( const in vec3 col, const in vec3 pos, const in vec3 rd, const in vec3 n, const in float spec, 
                           const in vec3 sunc, const in vec3 upc, const in vec3 reflc ) {
            vec3 sunDirection =  terrainTransform(SUN_DIRECTION);
            float dif = diffuse( n, sunDirection );
            float bac = diffuse( n, vec3(-sunDirection.x, sunDirection.y, -sunDirection.z) );
            float sha = terrainCalcShadow( pos, sunDirection );
            float amb = clamp( n.y,0.0,1.0);
                
            vec3 lin  = vec3(0.0);
            lin += 2.*dif*sunc*vec3( sha, sha*sha*0.1+0.9*sha, sha*sha*0.2+0.8*sha );
            lin += 0.2*amb*upc;
            lin += 0.08*bac*clamp(vec3(1.)-sunc, vec3(0.), vec3(1.));
            return mix( col*lin*3., reflc, spec*fresnel(n,-terrainTransform(rd),5.0) );
        }
        
        vec3 terrainGetColor( const in vec3 pos, const in vec3 rd, const in float t, const in vec3 sunc, const in vec3 upc, const in vec3 reflc ) {
            vec3 nor = terrainCalcNormalHigh( pos, t );
            vec3 sor = terrainCalcNormalMed( pos, t );
                
            float spec = 0.005;
        
        #ifdef DISPLAY_TERRAIN_DETAIL
            float no = noise(5.*fbm(1.11*pos.xz));
        #else
            const float no = 0.;
        #endif
            float r = .5+.5*fbm(.95*pos.xz);
            vec3 col = (r*0.25+0.75)*0.9*mix( vec3(0.08,0.07,0.07), vec3(0.10,0.09,0.08), noise(0.4267*vec2(pos.x*2.,pos.y*9.8))+.01*no );
            col = mix( col, 0.20*vec3(0.45,.30,0.15)*(0.50+0.50*r),smoothstep(0.825,0.925,nor.y+.025*no) );
            col = mix( col, 0.15*vec3(0.30,.30,0.10)*(0.25+0.75*r),smoothstep(0.95,1.0,nor.y+.025*no) );
            col *= .88+.12*no;
                
            float s = nor.y + 0.03*pos.y + 0.35*fbm(0.05*pos.xz) - .35;
            float sf = fwidth(s) * 1.5;
            s = smoothstep(0.84-sf, 0.84+sf, s );
            col = mix( col, 0.29*vec3(0.62,0.65,0.7), s);
            nor = mix( nor, sor, 0.7*smoothstep(0.9, 0.95, s ) );
            spec = mix( spec, 0.45, smoothstep(0.9, 0.95, s ) );
        
               col = terrainShade( col, pos, rd, nor, spec, sunc, upc, reflc );
        
        #ifdef DISPLAY_LLAMEL
            col *= clamp( distance(pos.xz, llamelPosition().xz )*0.4, 0.4, 1.);
        #endif
            
            return col;
        }
        
        vec3 terrainTransformRo( const in vec3 ro ) {
            vec3 rom = terrainTransform(ro);
            rom.y -= EARTH_RADIUS - 100.;
            rom.xz *= 5.;
            rom.xz += vec2(-170.,50.)+vec2(-4.,.4)*time;    
            rom.y += (terrainLow( rom.xz ) - 86.)*clamp( 1.-1.*(length(ro)-EARTH_RADIUS), 0., 1.);
            return rom;
        }
        
        vec4 renderTerrain( const in vec3 ro, const in vec3 rd, inout vec3 intersection, inout vec3 n ) {    
            vec3 p,
            rom = terrainTransformRo(ro),
            rdm = terrainTransform(rd);
                
            float tmin = 10.0;
            float tmax = 3200.0;
            
            float res = terrainIntersect( rom, rdm, tmin, tmax );
            
            if( res > tmax ) {
                res = -1.;
            } else {
                vec3 pos =  rom+rdm*res;
                n = terrainCalcNormalMed( pos, res );
                n = terrainUntransform( n );
                
                intersection = ro+rd*res/100.;
            }
            return vec4(res, rom+rdm*res);
        }
        
        #endif
        
        //-----------------------------------------------------
        // LLamels by Eiffie
        //
        // https://www.shadertoy.com/view/ltsGz4
        //-----------------------------------------------------
        #ifdef DISPLAY_LLAMEL
        float llamelMapSMin(const in float a,const in float b,const in float k){
            float h=clamp(0.5+0.5*(b-a)/k,0.0,1.0);return b+h*(a-b-k+k*h);
        }
        
        float llamelMapLeg(vec3 p, vec3 j0, vec3 j3, vec3 l, vec4 r, vec3 rt){//z joint with tapered legs
            float lx2z=l.x/(l.x+l.z),h=l.y*lx2z;
            vec3 u=(j3-j0)*lx2z,q=u*(0.5+0.5*(l.x*l.x-h*h)/dot(u,u));
            q+=sqrt(max(0.0,l.x*l.x-dot(q,q)))*normalize(cross(u,rt));
            vec3 j1=j0+q,j2=j3-q*(1.0-lx2z)/lx2z;
            u=p-j0;q=j1-j0;
            h=clamp(dot(u,q)/dot(q,q),0.0,1.0);
            float d=length(u-q*h)-r.x-(r.y-r.x)*h;
            u=p-j1;q=j2-j1;
            h=clamp(dot(u,q)/dot(q,q),0.0,1.0);
            d=min(d,length(u-q*h)-r.y-(r.z-r.y)*h);
            u=p-j2;q=j3-j2;
            h=clamp(dot(u,q)/dot(q,q),0.0,1.0);
            return min(d,length(u-q*h)-r.z-(r.w-r.z)*h);
        }
        
        float llamelMap(in vec3 p) {
            const vec3 rt=vec3(0.0,0.0,1.0);
            p.y += 0.25*llamelScale;
            p.xz -= 0.5*llamelScale;
            p.xz = vec2(-p.z, p.x);
            vec3 pori = p;
                
            p /= llamelScale;
            
            vec2 c=floor(p.xz);
            p.xz=fract(p.xz)-vec2(0.5);
            p.y -= p.x*.04*llamelScale;
            float sa=sin(c.x*2.0+c.y*4.5+llamelTime*0.05)*0.15;
        
            float b=0.83-abs(p.z);
            float a=c.x+117.0*c.y+sign(p.x)*1.57+sign(p.z)*1.57+llamelTime,ca=cos(a);
            vec3 j0=vec3(sign(p.x)*0.125,ca*0.01,sign(p.z)*0.05),j3=vec3(j0.x+sin(a)*0.1,max(-0.25+ca*0.1,-0.25),j0.z);
            float dL=llamelMapLeg(p,j0,j3,vec3(0.08,0.075,0.12),vec4(0.03,0.02,0.015,0.01),rt*sign(p.x));
            p.y-=0.03;
            float dB=(length(p.xyz*vec3(1.0,1.75,1.75))-0.14)*0.75;
            a=c.x+117.0*c.y+llamelTime;ca=cos(a);sa*=0.4;
            j0=vec3(0.125,0.03+abs(ca)*0.03,ca*0.01),j3=vec3(0.3,0.07+ca*sa,sa);
            float dH=llamelMapLeg(p,j0,j3,vec3(0.075,0.075,0.06),vec4(0.03,0.035,0.03,0.01),rt);
            dB=llamelMapSMin(min(dL,dH),dB,clamp(0.04+p.y,0.0,1.0));
            a=max(abs(p.z),p.y)+0.05;
            return max(min(dB,min(a,b)),length(pori.xz-vec2(0.5)*llamelScale)-.5*llamelScale);
        }
        
        vec3 llamelGetNormal( in vec3 ro ) {
            vec2 e = vec2(1.0,-1.0)*0.001;
        
            return normalize( e.xyy*llamelMap( ro + e.xyy ) + 
                              e.yyx*llamelMap( ro + e.yyx ) + 
                              e.yxy*llamelMap( ro + e.yxy ) + 
                              e.xxx*llamelMap( ro + e.xxx ) );
        }
        
        vec4 renderLlamel( in vec3 ro, const in vec3 rd, const in vec3 sunc, const in vec3 upc, const in vec3 reflc ) {
            ro -= llamelPosition();
            float t=.1*hash(rd.xy),d,dm=10.0,tm;
            for(int i=0;i<36;i++){
                t+=d=llamelMap(ro+rd*t);
                if(d<dm){dm=d;tm=t;}
                if(t>1000.0 || d<0.00001)break;
            }
            dm=max(0.0,dm);
            if( dm < .02 ) {
                vec3 col = vec3(0.45,.30,0.15)*.2;
                vec3 pos = ro + rd*tm;
                vec3 nor = llamelGetNormal( pos );
                col = terrainShade( col, pos, rd, nor, .01, sunc, upc, reflc );        
                return vec4(col, clamp( 1.-(dm-0.01)/0.01,0., 1.) );
            }
            
            return vec4(0.);
        }
        #endif
        
        //-----------------------------------------------------
        // Clouds (by me ;))
        //-----------------------------------------------------
        
        vec4 renderClouds( const in vec3 ro, const in vec3 rd, const in float d, const in vec3 n, const in float land, 
                           const in vec3 sunColor, const in vec3 upColor, inout float shadow ) {
            vec3 intersection = ro+rd*d;
            vec3 cint = intersection*0.009;
            float rot = -.2*length(cint.xy) + .6*fbm( cint*.4,0.5,2.96 ) + .05*land;
        
            cint.xy = rotate( rot, cint.xy );
        
            vec3 cdetail = mod(intersection*3.23,vec3(50.));
            cdetail.xy = rotate( .25*rot, cdetail.xy );
        
            float clouds = 1.3*(fbm( cint*(1.+.02*noise(intersection)),0.5,2.96)+.4*land-.3);
        
        #ifdef DISPLAY_CLOUDS_DETAIL
            if( d < 200. ) {
                clouds += .3*(fbm(cdetail,0.5,2.96)-.5)*(1.-smoothstep(0.,200.,d));
            }
        #endif
        
            shadow = clamp(1.-clouds, 0., 1.);
        
            clouds = clamp(clouds, 0., 1.);
            clouds *= clouds;
            clouds *= smoothstep(0.,0.4,d);
        
            vec3 clbasecolor = vec3(1.);
            vec3 clcol = .1*clbasecolor*sunColor * vec3(specular(n,SUN_DIRECTION,rd,36.0));
            clcol += .3*clbasecolor*sunColor;
            clcol += clbasecolor*(diffuse(n,SUN_DIRECTION)*sunColor+upColor);  
            
            return vec4( clcol, clouds );
        }
        
        //-----------------------------------------------------
        // Planet (by me ;))
        //-----------------------------------------------------
        
        vec4 renderPlanet( const in vec3 ro, const in vec3 rd, const in vec3 up, inout float maxd ) {
            float d = iSphere( ro, rd, vec4( 0., 0., 0., EARTH_RADIUS ) );
        
            vec3 intersection = ro + rd*d;
            vec3 n = nSphere( intersection, vec4( 0., 0., 0., EARTH_RADIUS ) );
            vec4 res;
        
        #ifndef HIDE_TERRAIN
            bool renderTerrainDetail = length(ro) < EARTH_RADIUS+EARTH_ATMOSPHERE && 
                                       dot( terrainUntransform( vec3(0.,1.,0.) ), normalize(ro) ) > .9996;
        #endif
            bool renderSeaDetail     = d < 1. && dot( seaUntransform( vec3(0.,1.,0.) ), normalize(ro) ) > .9999; 
            float mixDetailColor = 0.;
                
            if( d < 0. || d > maxd) {
        #ifndef HIDE_TERRAIN
                if( renderTerrainDetail ) {
                       intersection = ro;
                    n = normalize( ro );
                } else {      
                    return vec4(0);
                }
        #else 
                  return vec4(0.);
        #endif
            }
            if( d > 0. ) {
                maxd = d;
            }
            float att = 0.;
            
            if( dot(n,SUN_DIRECTION) < -0.1 ) return vec4( 0., 0., 0., 1. );
            
            float dm = MAX, e = 0.;
            vec3 col, detailCol, nDetail = vec3(0.0);
            
            // normal and intersection 
        #ifndef HIDE_TERRAIN
            if( renderTerrainDetail ) {   
                res = renderTerrain( ro, rd, intersection, nDetail );
                if( res.x < 0. && d < 0. ) {
                    return vec4(0);
                }
                if( res.x >= 0. ) {
                    maxd = pow(res.x/4000.,4.)*50.;
                    e = -10.;
                }
                mixDetailColor = 1.-smoothstep(.75, 1., (length(ro)-EARTH_RADIUS) / EARTH_ATMOSPHERE);
                n = normalize( mix( n, nDetail, mixDetailColor ) );
            } else 
        #endif        
            if( renderSeaDetail ) {    
                float attsea = 0.0, mf = smoothstep(.5,1.,d);
        
                renderSea( ro, rd, nDetail, attsea );
        
                n = normalize(mix( nDetail, n, mf ));
                att = mix( attsea, att, mf );
            } else {
                e = fbm( .003*intersection+vec3(1.),0.4,2.96) + smoothstep(.85,.95, abs(intersection.z/EARTH_RADIUS));
        #ifndef HIDE_TERRAIN
                if( d < 1500. ) {
                    e += (-.03+.06* fbm( intersection*0.1,0.4,2.96))*(1.-d/1500.);
                }
        #endif  
            }
            
            vec3 sunColor = .25*renderAtmosphericLow( intersection, SUN_DIRECTION).xyz;  
            vec3 upColor = 2.*renderAtmosphericLow( intersection, n).xyz;  
            vec3 reflColor = renderAtmosphericLow( intersection, reflect(rd,n)).xyz; 
                         
            // color  
        #ifndef HIDE_TERRAIN
            if(renderTerrainDetail ) {
                detailCol = col =  terrainGetColor(res.yzw, rd, res.x, sunColor, upColor, reflColor);
                d = 0.;
            }   
        #endif
             
            if( mixDetailColor < 1. ) {
                if( e < .45 ) {
                    // sea
                    col = seaGetColor(n,rd,SUN_DIRECTION, att, sunColor, upColor, reflColor);    
                } else {
                    // planet (land) far
                    float land1 = max(0.1, fbm( intersection*0.0013,0.4,2.96) );
                    float land2 = max(0.1, fbm( intersection*0.0063,0.4,2.96) );
                    float iceFactor = abs(pow(intersection.z/EARTH_RADIUS,13.0))*e;
        
                    vec3 landColor1 = vec3(0.43,0.65,0.1) * land1;
                    vec3 landColor2 = RING_COLOR_1 * land2;
                    vec3 mixedLand = (landColor1 + landColor2)* 0.5;
                    vec3 finalLand = mix(mixedLand, vec3(7.0, 7.0, 7.0) * land1 * 1.5, max(iceFactor+.02*land2-.02, 0.));
        
                    col = (diffuse(n,SUN_DIRECTION)*sunColor+upColor)*finalLand*.75;
        #ifdef HIGH_QUALITY
                    col *= (.5+.5*fbm( intersection*0.23,0.4,2.96) );
        #endif
                }
            }
            
            if( mixDetailColor > 0. ) {
                col = mix( col, detailCol, mixDetailColor );
            }
                
        #ifdef DISPLAY_LLAMEL
            if(renderTerrainDetail ) {
                vec3 rom = terrainTransformRo(ro),
                rdm = terrainTransform(rd);
                d = iSphere( rom, rdm, vec4( llamelPosition(), llamelScale*3. ) );
                if( d > 0. ) {
                    vec4 llamel = renderLlamel( rom+rdm*d, rdm, sunColor, upColor, reflColor );
                    col = mix(col, llamel.rgb, llamel.a);
                }
            }
        #endif
            
            d = iSphere( ro, rd, vec4( 0., 0., 0., EARTH_RADIUS+EARTH_CLOUDS ) );
            if( d > 0. ) { 
                float shadow = 0.;
                vec4 clouds = renderClouds( ro, rd, d, n, e, sunColor, upColor, shadow);
                col *= shadow; 
                col = mix( col, clouds.rgb, clouds.w );
            }
            
            float m = MAX;
            col *= (1. - renderRingFarShadow( ro+rd*d, SUN_DIRECTION ) );
        
             return vec4( col, 1. ); 
        }
        
        //-----------------------------------------------------
        // Lens flare by musk
        //
        // https://www.shadertoy.com/view/4sX3Rs
        //-----------------------------------------------------
        
        vec3 lensFlare( const in vec2 uv, const in vec2 pos) {
            vec2 main = uv-pos;
            vec2 uvd = uv*(length(uv));
            
            float f0 = 1.5/(length(uv-pos)*16.0+1.0);
            
            float f1 = max(0.01-pow(length(uv+1.2*pos),1.9),.0)*7.0;
        
            float f2 = max(1.0/(1.0+32.0*pow(length(uvd+0.8*pos),2.0)),.0)*00.25;
            float f22 = max(1.0/(1.0+32.0*pow(length(uvd+0.85*pos),2.0)),.0)*00.23;
            float f23 = max(1.0/(1.0+32.0*pow(length(uvd+0.9*pos),2.0)),.0)*00.21;
            
            vec2 uvx = mix(uv,uvd,-0.5);
            
            float f4 = max(0.01-pow(length(uvx+0.4*pos),2.4),.0)*6.0;
            float f42 = max(0.01-pow(length(uvx+0.45*pos),2.4),.0)*5.0;
            float f43 = max(0.01-pow(length(uvx+0.5*pos),2.4),.0)*3.0;
            
            vec3 c = vec3(.0);
            
            c.r+=f2+f4; c.g+=f22+f42; c.b+=f23+f43;
            c = c*.5 - vec3(length(uvd)*.05);
            c+=vec3(f0);
            
            return c;
        }
        
        //-----------------------------------------------------
        // cameraPath
        //-----------------------------------------------------
        
        vec3 pro, pta, pup;
        float dro, dta, dup;
        
        void camint( inout vec3 ret, const in float t, const in float duration, const in vec3 dest, inout vec3 prev, inout float prevt ) {
            if( t >= prevt && t <= prevt+duration ) {
                ret = mix( prev, dest, smoothstep(prevt, prevt+duration, t) );
            }
            prev = dest;
            prevt += duration;
        }
        
        void cameraPath( in float t, out vec3 ro, out vec3 ta, out vec3 up ) {
        #ifndef HIDE_TERRAIN
            //float t=time;
              t = mod( t, 92. );
        #else
              t = mod( t, 66. );
        #endif
            dro = dta = dup = 0.;
        
            pro = ro = vec3(900. ,7000. ,1500. );
            pta = ta = vec3(    0. ,    0. ,   0. );
            pup = up = vec3(    0. ,    0.4,   1. ); 
           
            camint( ro, t, 5., vec3(-4300. ,-1000. , 500. ), pro, dro );
            camint( ta, t, 5., vec3(    0. ,    0. ,   0. ), pta, dta );
            camint( up, t, 7., vec3(    0. ,    0.1,   1. ), pup, dup ); 
         
            camint( ro, t, 3., vec3(-1355. , 1795. , 1.2 ), pro, dro );
            camint( ta, t, 1., vec3(    0. , 300. ,-600. ), pta, dta );
            camint( up, t, 6., vec3(    0. ,  0.1,    1. ), pup, dup );
        
            camint( ro, t, 10., vec3(-1355. , 1795. , 1.2 ), pro, dro );
            camint( ta, t, 14., vec3(    0. , 100. ,   600. ), pta, dta );
            camint( up, t, 13., vec3(    0. ,  0.3,    1. ), pup, dup );
            
            vec3 roe = seaUntransform( vec3( 0., EARTH_RADIUS+0.004, 0. ) );
            vec3 upe = seaUntransform( vec3( 0., 1., 0. ) );
            
            camint( ro, t, 7.,roe, pro, dro );
            camint( ta, t, 7., vec3( EARTH_RADIUS + 0., EARTH_RADIUS - 500., 500. ), pta, dta );
            camint( up, t, 6., upe, pup, dup );
                
            camint( ro, t, 17.,roe, pro, dro );
            camint( ta, t, 17., vec3( EARTH_RADIUS + 500., EARTH_RADIUS + 1300., -100. ), pta, dta );
            camint( up, t, 18., vec3(.0,1.,1.), pup, dup );
            
            camint( ro, t, 11., vec3(  3102. ,  0. , 1450. ), pro, dro );
            camint( ta, t, 4., vec3(    0. ,   -100. ,   0. ), pta, dta );
            camint( up, t, 8., vec3(    0. ,    0.15,   1. ), pup, dup ); 
        #ifndef HIDE_TERRAIN    
            roe = terrainUntransform( vec3( 0., EARTH_RADIUS+0.004, 0. ) );
            upe = terrainUntransform( vec3( 0., 1., 0. ) );
            
            camint( ro, t, 7., roe, pro, dro );
            camint( ta, t, 12., vec3( -EARTH_RADIUS, EARTH_RADIUS+200., 100.), pta, dta );
            camint( up, t, 2., upe, pup, dup );
                
            roe = terrainUntransform( vec3( 0., EARTH_RADIUS+0.001, 0. ) );
            camint( ro, t, 17.,roe, pro, dro );
            camint( ta, t, 18., roe + vec3( 5000., EARTH_RADIUS-100., -2000.), pta, dta );
            camint( up, t, 18., vec3(.0,1.,1.), pup, dup );
                
            roe = terrainUntransform( vec3( 0., EARTH_RADIUS+1.8, 0. ) );
            camint( ro, t, 4.,roe, pro, dro );
            camint( ta, t, 4.5, roe + vec3( EARTH_RADIUS, EARTH_RADIUS+2000., -30.), pta, dta );
            camint( up, t, 4., vec3(.0,1.,1.), pup, dup );
        #endif    
            camint( ro, t, 10., vec3(900. ,7000. , 1500. ), pro, dro );
            camint( ta, t, 2., vec3(    0. ,    0. ,   0. ), pta, dta );
            camint( up, t, 10., vec3(    0. ,    0.4,   1. ), pup, dup ); 
            
            up = normalize( up );
        }
        
        //-----------------------------------------------------
        // mainImage
        //-----------------------------------------------------
        
        void main() {
            vec2 uv = gl_FragCoord.xy / resolution.xy;
            
            vec2 p = -1.0 + 2.0 * (gl_FragCoord.xy) / resolution.xy;
            p.x *= resolution.x/resolution.y;
            
            vec3 col;
            
        // black bands
            vec2 bandy = vec2(.1,.9);
            if( uv.y < bandy.x || uv.y > bandy.y ) {
                col = vec3(0.);
            } else {
                // camera
                vec3 ro, ta, up;
                cameraPath( time*.7, ro, ta, up );
        
                vec3 ww = normalize( ta - ro );
                vec3 uu = normalize( cross(ww,up) );
                vec3 vv = normalize( cross(uu,ww));
                vec3 rd = normalize( -p.x*uu + p.y*vv + 2.2*ww );
        
                float maxd = MAX;  
                col = renderStars( rd ).xyz;
        
                vec4 planet = renderPlanet( ro, rd, up, maxd );       
                if( planet.w > 0. ) col.xyz = planet.xyz;
        
                float atmosphered = maxd;
                vec4 atmosphere = .85*renderAtmospheric( ro, rd, atmosphered );
                col = col * (1.-atmosphere.w ) + atmosphere.xyz; 
        
                vec4 ring = renderRing( ro, rd, maxd );
                if( ring.w > 0. && atmosphered < maxd ) {
                   ring.xyz = ring.xyz * (1.-atmosphere.w ) + atmosphere.xyz; 
                }
                col = col * (1.-ring.w ) + ring.xyz;
        
        #ifdef DISPLAY_CLOUDS
                float lro = length(ro);
                if( lro < EARTH_RADIUS+EARTH_CLOUDS*1.25 ) {
                    vec3 sunColor = 2.*renderAtmosphericLow( ro, SUN_DIRECTION);  
                    vec3 upColor = 4.*renderAtmosphericLow( ro, vec3(-SUN_DIRECTION.x, SUN_DIRECTION.y, -SUN_DIRECTION.z));  
        
                    if( lro < EARTH_RADIUS+EARTH_CLOUDS ) {
                        // clouds
                        float d = iCSphereF( ro, rd, EARTH_RADIUS + EARTH_CLOUDS );
                        if( d < maxd ) {
                            float shadow = 0.;
                            vec4 clouds = renderClouds( ro, rd, d, normalize(ro), 0., sunColor, upColor, shadow );
                            clouds.w *= 1.-smoothstep(0.8*EARTH_CLOUDS,EARTH_CLOUDS,lro-EARTH_RADIUS);
                            col = mix(col, clouds.rgb, clouds.w * (1.-smoothstep( 10., 30., d)) );
                        }
                    }
                    float offset = lro-EARTH_RADIUS-EARTH_CLOUDS;
                    col = mix( col, .5*sunColor, .15*abs(noise(offset*100.))*clamp(1.-4.*abs(offset)/EARTH_CLOUDS, 0., 1.) );
                }
        #endif 
        
                // post processing
                col = pow( clamp(col,0.0,1.0), vec3(0.4545) );
                col *= vec3(1.,0.99,0.95);   
                col = clamp(1.06*col-0.03, 0., 1.);      
        
                vec2 sunuv =  2.7*vec2( dot( SUN_DIRECTION, -uu ), dot( SUN_DIRECTION, vv ) );
                float flare = dot( SUN_DIRECTION, normalize(ta-ro) );
                col += vec3(1.4,1.2,1.0)*lensFlare(p, sunuv)*clamp( flare+.3, 0., 1.);
        
                uv.y = (uv.y-bandy.x)*(1./(bandy.y-bandy.x));
                col *= 0.5 + 0.5*pow( 16.0*uv.x*uv.y*(1.0-uv.x)*(1.0-uv.y), 0.1 ); 
            }
            gl_FragColor = vec4( col ,1.0);
        }
        // end Conversion ; Gigatron 
        `
  const scene = new THREE.Scene()

  const camera = new THREE.PerspectiveCamera(75, dom.offsetWidth / dom.offsetHeight, 0.01, 1000)
  camera.position.set(20, 20, 20)

  const render = new THREE.WebGLRenderer()
  render.setSize(dom.offsetWidth, dom.offsetHeight)
  render.shadowMap.enabled = true

  dom.appendChild(render.domElement)

  const axes = new THREE.AxesHelper(100)
  scene.add(axes)

  const cubeGeometry = new THREE.BoxGeometry(50, 50, 50)

  const meshMaterial1 = createMaterial(vertexShader, fragmentShader1)
  const meshMaterial2 = createMaterial(vertexShader, fragmentShader2)
  const meshMaterial3 = createMaterial(vertexShader, fragmentShader3)
  const meshMaterial4 = createMaterial(vertexShader, fragmentShader4)
  const meshMaterial5 = createMaterial(vertexShader, fragmentShader5)
  const meshMaterial6 = createMaterial(vertexShader, fragmentShader6)

  const material = [meshMaterial1, meshMaterial2, meshMaterial3, meshMaterial4, meshMaterial5, meshMaterial6]
  const cube = new THREE.Mesh(cubeGeometry, material)
  scene.add(cube)

  const ambientLight = new THREE.AmbientLight(0x0c0c0c)
  scene.add(ambientLight)

  const planeGeometry = new THREE.PlaneGeometry(100, 100)
  const planeMaterial = new THREE.MeshLambertMaterial({ color: 0xAAAAAA })
  const plane = new THREE.Mesh(planeGeometry, planeMaterial)

  plane.rotation.x = -0.5 * Math.PI
  plane.position.set(15, 0, 0)
  plane.receiveShadow = true

  scene.add(plane)

  camera.position.x = -20
  camera.position.y = 20
  camera.position.z = 30
  camera.lookAt(scene.position)
  scene.add(camera)

  const controls = new OrbitControls(camera, render.domElement)
  controls.update()

  const spotLight = new THREE.SpotLight(0xffffff)
  spotLight.position.set(0, 30, 60)
  spotLight.castShadow = true
  spotLight.intensity = 0.6
  scene.add(spotLight)

  let step = 0

  renderScene()

  function renderScene () {
    controls.update()

    cube.rotation.y = step += 0.01
    cube.rotation.x = step
    cube.rotation.z = step

    cube.material.forEach(function (e) {
      e.uniforms.time.value += 0.01
    })

    requestAnimationFrame(renderScene)
    render.render(scene, camera)
  }

  window.addEventListener('resize', onWindowResize, false)

  function onWindowResize () {
    camera.aspect = window.innerWidth / window.innerHeight
    camera.updateProjectionMatrix()
    render.setSize(window.innerWidth, window.innerHeight)
  }

  function createMaterial (vertexShader: string, fragmentShader: string) {
    const vertShader = vertexShader
    const fragShader = fragmentShader

    const uniforms = {
      time: {
        type: 'f',
        value: 0.2
      },
      scale: {
        type: 'f',
        value: 0.2
      },
      alpha: {
        type: 'f',
        value: 0.6
      },
      resolution: {
        type: 'v2',
        value: new THREE.Vector2()
      }
    }

    uniforms.resolution.value.x = window.innerWidth
    uniforms.resolution.value.y = window.innerHeight

    const meshMaterial = new THREE.ShaderMaterial({
      uniforms: uniforms,
      vertexShader: vertShader,
      fragmentShader: fragShader,
      transparent: true
    })

    return meshMaterial
  }

  render.setAnimationLoop(anmation)

  function anmation () {
    stats.update()
    cube.rotation.y = step += 0.01
    cube.rotation.x = step
    cube.rotation.z = step

    cube.material.forEach(function (e) {
      e.uniforms.time.value += 0.01
    })
    render.render(scene, camera)
  }

  return { camera, scene, render }
}

export {
  createCourse26
}
